Python個(gè)人博客程序開發(fā)實(shí)例框架設(shè)計(jì)
本文要學(xué)習(xí)的示例程序是一個(gè)個(gè)人博客程序:Bluelog。博客是典型的 CMS
(Content Management System
,內(nèi)容管理系統(tǒng)),通常由兩部分組成:一部分是博客前臺(tái),用來展示開放給所有用戶的博客內(nèi)容;另一部分是博客后臺(tái),這部分內(nèi)容僅開放給博客管理員,用來對博客資源進(jìn)行添加、修改和刪除等操作。
1.數(shù)據(jù)庫(models.py)
from datetime import datetime from flask_login import UserMixin from werkzeug.security import generate_password_hash, check_password_hash from bluelog.extensions import db
1.1 管理員 Admin
class Admin(db.Model, UserMixin): id = db.Column(db.Integer, primary_key=True) # 主鍵字段 username = db.Column(db.String(20)) # 用戶名 password_hash = db.Column(db.String(128)) # 密碼散列值 blog_title = db.Column(db.String(60)) # 博客標(biāo)題 blog_sub_title = db.Column(db.String(100)) # 博客副標(biāo)題 name = db.Column(db.String(30)) # 用戶姓名 about = db.Column(db.Text) # 關(guān)于信息 def set_password(self, password): self.password_hash = generate_password_hash(password) def validate_password(self, password): return check_password_hash(self.password_hash, password)
1.2 分類 Category
class Category(db.Model): id = db.Column(db.Integer, primary_key=True) # 主鍵字段 name = db.Column(db.String(30), unique=True) # 分類名稱 posts = db.relationship('Post', back_populates='category') # 分類和文章之間是一對多關(guān)系 def delete(self): default_category = Category.query.get(1) posts = self.posts[:] for post in posts: post.category = default_category db.session.delete(self) db.session.commit()
1.3 文章 Post
class Post(db.Model): id = db.Column(db.Integer, primary_key=True) # 主鍵字段 title = db.Column(db.String(60)) # 標(biāo)題 body = db.Column(db.Text) # 正文 timestamp = db.Column(db.DateTime, default=datetime.utcnow, index=True) # 時(shí)間戳 can_comment = db.Column(db.Boolean, default=True) # 是否能被評(píng)論 category_id = db.Column(db.Integer, db.ForeignKey('category.id')) # 所屬分類,外鍵字段 category = db.relationship('Category', back_populates='posts') # 分類和文章之間是一對多關(guān)系 comments = db.relationship('Comment', back_populates='post', cascade='all, delete-orphan') # 文章和評(píng)論是一對多關(guān)系
Comment
模型中創(chuàng)建的外鍵字段 post_id
存儲(chǔ) Post
記錄的主鍵值。我們在這里設(shè)置了級(jí)聯(lián)刪除,也就是說,當(dāng)某個(gè)文章記錄被刪除時(shí),該文章所屬的所有評(píng)論也會(huì)一并被刪除,所以在刪除文章時(shí)不用手動(dòng)刪除對應(yīng)的評(píng)論。
1.4 評(píng)論 Comment
class Comment(db.Model): id = db.Column(db.Integer, primary_key=True) # 主鍵字段 author = db.Column(db.String(30)) # 作者 email = db.Column(db.String(254)) # 電子郵件 site = db.Column(db.String(255)) # 站點(diǎn) body = db.Column(db.Text) # 正文 from_admin = db.Column(db.Boolean, default=False) # 是否是管理員的評(píng)論 reviewed = db.Column(db.Boolean, default=False) # 是否通過審核 timestamp = db.Column(db.DateTime, default=datetime.utcnow, index=True) # 時(shí)間戳 replied_id = db.Column(db.Integer, db.ForeignKey('comment.id')) # 外鍵 post_id = db.Column(db.Integer, db.ForeignKey('post.id')) # 外鍵 post = db.relationship('Post', back_populates='comments') # 文章和評(píng)論是一對多關(guān)系 replies = db.relationship('Comment', back_populates='replied', cascade='all, delete-orphan') # 設(shè)置級(jí)聯(lián)刪除 replied = db.relationship('Comment', back_populates='replies', remote_side=[id]) # 自關(guān)聯(lián)多對一需用 remote_side=id 指定 ‘一' 的一方
博客程序中的評(píng)論要支持存儲(chǔ)回復(fù)。我們想要為評(píng)論添加回復(fù),并在獲取某個(gè)評(píng)論時(shí)可以通過關(guān)系屬性獲得相對應(yīng)的回復(fù),這樣就可以在模板中顯示出評(píng)論之間的對應(yīng)關(guān)系。那么回復(fù)如何存儲(chǔ)在數(shù)據(jù)庫中呢?
你當(dāng)然可以再為回復(fù)創(chuàng)建一個(gè) Reply 模型,然后使用一對多關(guān)系將評(píng)論和回復(fù)關(guān)聯(lián)起來。但是我們將介紹一個(gè)更簡單的解決辦法,因?yàn)榛貜?fù)本身也是評(píng)論,如果可以在評(píng)論模型內(nèi)建立層級(jí)關(guān)系,那么就可以在一個(gè)模型中表示評(píng)論和回復(fù)。
這種在同一個(gè)模型內(nèi)的一對多關(guān)系在 SQLAlchemy 中被稱為鄰接列表關(guān)系(Adjacency List Relationship)。具體來說,我們需要在 Comment 模型中添加一個(gè)外鍵指向它自身。這樣我們就得到一種層級(jí)關(guān)系:每個(gè)評(píng)論對象都可以包含多個(gè)子評(píng)論,即回復(fù)。
這個(gè)關(guān)系和我們之前熟悉的一對多關(guān)系基本相同。仔細(xì)回想一下一對多關(guān)系的設(shè)置,我們需要在 “多” 這一側(cè)定義外鍵,這樣 SQLAlchemy 就會(huì)知道哪邊是 “多” 的一側(cè)。這時(shí)關(guān)系對 “多” 這一側(cè)來說就是多對一關(guān)系。但是在鄰接列表關(guān)系中,關(guān)系的兩側(cè)都在同一個(gè)模型中,這時(shí) SQLAlchemy 就無法分辨關(guān)系的兩側(cè)。在這個(gè)關(guān)系函數(shù)中,通過將 remote_side
參數(shù)設(shè)為 id
字段,我們就把 id
字段定義為關(guān)系的遠(yuǎn)程側(cè)(Remote Side),而 replied_id
就相應(yīng)地變?yōu)楸镜貍?cè)(Local Side),這樣反向關(guān)系就被定義為多對一,即多個(gè)回復(fù)對應(yīng)一個(gè)父評(píng)論。
集合關(guān)系屬性 replies
中的 cascade
參數(shù)設(shè)為 all
,因?yàn)槲覀兤谕男Ч?,?dāng)父評(píng)論被刪除時(shí),所有的子評(píng)論也隨之刪除。
1.5 社交鏈接 Link
程序還包含了一個(gè)添加社交鏈接的功能。
class Link(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(30)) url = db.Column(db.String(255))
2.生成虛擬數(shù)據(jù)(fakes.py)
from faker import Faker fake = Faker()
def fake_admin(): def fake_categories(count=10): def fake_posts(count=50): def fake_links():
3.模板
3.1 模板上下文
在基模板的導(dǎo)航欄以及博客主頁中需要使用博客的標(biāo)題、副標(biāo)題等存儲(chǔ)在管理員對象上的數(shù)據(jù),為了避免在每個(gè)視圖函數(shù)中渲染模板時(shí)傳入這些數(shù)據(jù),我們在模板上下文處理函數(shù)中向模板上下文添加了管理員對象變量(admin)。另外,在多個(gè)頁面中都包含的邊欄中包含分類列表,我們也把分類數(shù)據(jù)傳入到模板上下文中。
from bluelog.models import Admin, Category def create_app(config_name=None): ... register_template_context(app) return app def register_template_context(app): @app.context_processor def make_template_context(): admin = Admin.query.first() categories = Category.query.order_by(Category.name).all() return dict(admin=admin, categories=categories)
在基模板 base.html
和主頁模板 index.html
中,我們可以直接使用傳入的 admin
對象獲取博客的標(biāo)題和副標(biāo)題。
<div class="page-header"> <h1 class="display-3">{{ admin.blog_title|default('Blog Title') }}</h1> <h4 class="text-muted"> {{ admin.blog_sub_title|default('Blog Subtitle') }}</h4> </div>
3.2 渲染導(dǎo)航鏈接
導(dǎo)航欄上的按鈕應(yīng)該在對應(yīng)的頁面顯示激活狀態(tài)。舉例來說,當(dāng)用戶單擊導(dǎo)航欄上的 “關(guān)于” 按鈕打開關(guān)于頁面時(shí),“關(guān)于” 按鈕應(yīng)該高亮顯示。Bootstrap 為導(dǎo)航鏈接提供了一個(gè) active
類來顯示激活狀態(tài),我們需要為當(dāng)前頁面對應(yīng)的按鈕添加 active
類。
這個(gè)功能可以通過判斷請求的端點(diǎn)來實(shí)現(xiàn),對 request
對象調(diào)用 endpoint
屬性即可獲得當(dāng)前的請求端點(diǎn)。如果當(dāng)前的端點(diǎn)與導(dǎo)航鏈接指向的端點(diǎn)相同,就為它添加 active
類,顯示激活樣式。
<li {% if request.endpoint == 'blog.index' %}class="active"{% endif %}> <a href="{{ url_for('blog.index') }}" rel="external nofollow" >Home</a> </li>
有些教程中會(huì)使用 endswith()
方法來比較端點(diǎn)結(jié)尾。但是藍(lán)本擁有獨(dú)立的端點(diǎn)命名空間,即 “<藍(lán)本名>.<端點(diǎn)名>”,不同的端點(diǎn)可能會(huì)擁有相同的結(jié)尾,比如 blog.index
和 auth.index
,這時(shí)使用 endswith()
會(huì)導(dǎo)致判斷錯(cuò)誤,所以最妥善的做法是比較完整的端點(diǎn)值。
不過在 Bluelog
的模板中我們并沒有使用這個(gè) nav_link()
宏,因?yàn)?Bootstrap-Flask
提供了一個(gè)更加完善的 render_nav_item()
宏,它的用法和我們創(chuàng)建的 nav_link()
宏基本相同。這個(gè)宏可以在模板中通過 bootstrap/nav.html
路徑導(dǎo)入,它支持的常用參數(shù)如下表所示。
3.3 Flash消息分類
我們目前的 Flash
消息應(yīng)用了 Bootstrap 的 alert-info
樣式,單一的樣式使消息的類別和等級(jí)難以區(qū)分,更合適的做法是為不同類別的消息應(yīng)用不同的樣式。比如,當(dāng)用戶訪問出錯(cuò)時(shí)顯示一個(gè)黃色的警告消息;而普通的提示信息則使用藍(lán)色的默認(rèn)樣式。Bootstrap 為提醒消息(Alert)提供了 8 種基本的樣式類,即 alert-primary
、alert-secondary
、alert-success
、alert-danger
、alert-warning
、alert-light
、alert-dark
。
要開啟消息分類,我們首先要在消息渲染函數(shù) get_flashed_messages
中將 with_categories
參數(shù)設(shè)為 True
。這時(shí)會(huì)把消息迭代為一個(gè)類似于(分類,消息)的元組,我們使用消息分類字符來構(gòu)建樣式類。
<main class="container"> {% for message in get_flashed_messages(with_categories=True) %} <div class="alert alert-{{ message[0] }}" role="alert"> <button type="button" class="close" data-dismiss="alert">×</button> {{ message[1] }} </div> {% endfor %} ... </main>
4.表單(forms.py)
Bluelog 中主要包含下面這些表單:登錄表單、文章表單、分類表單、評(píng)論表單、博客設(shè)置表單。這里我們僅介紹登錄表單、文章表單、分類表單和評(píng)論表單,其他的表單在實(shí)現(xiàn)上基本相同,不再詳細(xì)介紹。
刪除資源也需要使用表單來實(shí)現(xiàn),這里之所以沒有創(chuàng)建表單類,是因?yàn)楹竺嫖覀儠?huì)介紹在實(shí)現(xiàn)刪除操作時(shí)為表單實(shí)現(xiàn) CSRF
保護(hù)的更方便的做法,屆時(shí)表單可以手動(dòng)在模板中寫出。
4.1 登錄表單
from flask_wtf import FlaskForm from wtforms import StringField, PasswordField, SubmitField, BooleanField from wtforms.validators import DataRequired class LoginForm(FlaskForm): username = StringField('Username', validators=[DataRequired(), Length(1, 20)]) password = PasswordField('Password', validators=[DataRequired(), Length(1, 128)]) remember = BooleanField('Remember me') submit = SubmitField('Log in')
登錄表單由用戶名字段 username
、密碼字段 password
、“記住我” 復(fù)選框 remember
和 “提交” 按鈕 submit
組成。
4.2 文章表單
from flask_ckeditor import CKEditorField from flask_wtf import FlaskForm from wtforms import StringField, SubmitField, SelectField from wtforms.validators import DataRequired, Length from bluelog.models import Category class PostForm(FlaskForm): title = StringField('Title', validators=[DataRequired(), Length(1, 60)]) category = SelectField('Category', coerce=int, default=1) body = CKEditorField('Body', validators=[DataRequired()]) submit = SubmitField() def __init__(self, *args, **kwargs): super(PostForm, self).__init__(*args, **kwargs) self.category.choices = [(category.id, category.name) for category in Category.query.order_by(Category.name).all()]
文章創(chuàng)建表單由標(biāo)題字段 title
、分類選擇字段 category
、正文字段 body
和 “提交” 按鈕組成,其中正文字段使用 Flask-CKEditor
提供的 CKEditorField
字段。
下拉列表字段使用 WTForms 提供的 SelectField
類來表示 HTML 中的 標(biāo)簽。下拉列表的選項(xiàng)(即 標(biāo)簽)通過參數(shù) choices
指定。choices
必須是一個(gè)包含兩元素元組的列表,列表中的元組分別包含選項(xiàng)值和選項(xiàng)標(biāo)簽。我們使用分類的 id
作為選項(xiàng)值,分類的名稱作為選項(xiàng)標(biāo)簽,這兩個(gè)值通過迭代 Category.query.order_by(Category.name).all()
返回的分類記錄實(shí)現(xiàn)。選擇值默認(rèn)為字符串類型,我們使用 coerce
關(guān)鍵字指定數(shù)據(jù)類型為整型。default
用來設(shè)置默認(rèn)的選項(xiàng)值,我們將其指定為 1,即默認(rèn)分類的 id
。
因?yàn)?Flask-SQLAlchemy
依賴于程序上下文才能正常工作(內(nèi)部使用 current_app
獲取配置信息),所以這個(gè)查詢調(diào)用要放到構(gòu)造方法中執(zhí)行,在構(gòu)造方法中對 self.category.choices
賦值的效果和在類中實(shí)例化 SelectField
類并設(shè)置 choices
參數(shù)相同。
4.3 分類表單
from wtforms import StringField, SubmitField, ValidationError from wtforms import DataRequired from bluelog.models import Category class CategoryForm(FlaskForm): name = StringField('Name', validators=[DataRequired(), Length(1, 30)]) submit = SubmitField() def validate_name(self, field): if Category.query.filter_by(name=field.data).first(): raise ValidationError('Name already in use.')
分類創(chuàng)建字段僅包含分類名稱字段(name)和提交字段。分類的名稱要求不能重復(fù),為了避免寫入重復(fù)的分類名稱導(dǎo)致數(shù)據(jù)庫出錯(cuò),我們在 CategoryForm
類中添加了一個(gè) validate_name
方法,作為 name
字段的自定義行內(nèi)驗(yàn)證器,它將在驗(yàn)證 name
字段時(shí)和其他驗(yàn)證函數(shù)一起調(diào)用。在這個(gè)驗(yàn)證方法中,我們使用字段的值 filed.data
作為 name
列的參數(shù)值進(jìn)行查詢,如果查詢到已經(jīng)存在同名記錄,那么就拋出 ValidationError
異常,傳遞錯(cuò)誤消息作為參數(shù)。
4.4 評(píng)論表單
from flask_wtf import FlaskForm from wtforms import StringField, SubmitField, TextAreaField from wtforms.validators import DataRequired, Email, URL, Length, Optional class CommentForm(FlaskForm): author = StringField('Name', validators=[DataRequired(), Length(1, 30)]) email = StringField('Email', validators=[DataRequired(), Email(), Length(1, 254)]) site = StringField('Site', validators=[Optional(), URL(), Length(0, 255)]) body = TextAreaField('Comment', validators=[DataRequired()]) submit = SubmitField()
在這個(gè)表單中,email
字段使用了用于驗(yàn)證電子郵箱地址的 Email
驗(yàn)證器。另外,因?yàn)樵u(píng)論者的站點(diǎn)是可以留空的字段,所以我們使用 Optional
驗(yàn)證器來使字段可以為空。site
字段使用 URL
驗(yàn)證器確保輸入的數(shù)據(jù)為有效的 URL
。
和匿名用戶的表單不同,管理員不需要填寫諸如姓名、電子郵箱等字段。我們單獨(dú)為管理員創(chuàng)建了一個(gè)表單類,這個(gè)表單類繼承自 CommentForm
類。
class AdminCommentForm(CommentForm): author = HiddenField() email = HiddenField() site = HiddenField()
在這個(gè)表單中,姓名、Email、站點(diǎn)字段使用 HiddenField
類重新定義。這個(gè)類型代表隱藏字段,即 HTML 中的 < input type=“hidden” >。
5.視圖函數(shù)(blueprints:admin、auth、blog)
在上面我們已經(jīng)創(chuàng)建了所有必須的模型類、模板文件和表單類。經(jīng)過程序規(guī)劃和設(shè)計(jì)后,我們可以創(chuàng)建大部分視圖函數(shù)。這些視圖函數(shù)暫時(shí)沒有實(shí)現(xiàn)具體功能,僅渲染對應(yīng)的模板,或是重定向到其他視圖。以 blog
藍(lán)本為例。
from flask import render_template, Blueprint blog_bp = Blueprint('blog', __name__) @blog_bp.route('/') def index(): return render_template('blog/index.html') @blog_bp.route('/about') def about(): return render_template('blog/about.html') @blog_bp.route('/category/<int:category_id>') def show_category(category_id): return render_template('blog/category.html') @blog_bp.route('/post/<int:post_id>', methods=['GET', 'POST']) def show_post(post_id): return render_template('blog/post.html')
和 blog
藍(lán)本類似,我們在 blueprints
子包中創(chuàng)建了 auth.py
、admin.py
腳本,這些腳本中分別創(chuàng)建了 auth
和 admin
藍(lán)本,藍(lán)本實(shí)例的名稱分別為 auth_bp
和 admin_bp
。
6.電子郵件支持(emails.py)
因?yàn)椴┛鸵С衷u(píng)論,所以我們需要在文章有了新評(píng)論后發(fā)送郵件通知管理員。而且,當(dāng)管理員回復(fù)了讀者的評(píng)論后,也需要發(fā)送郵件提醒讀者。
因?yàn)猷]件的內(nèi)容很簡單,我們將直接在發(fā)信函數(shù)中寫出正文內(nèi)容,這里只提供了 HTML 正文。我們有兩個(gè)需要使用電子郵件的場景:
- 當(dāng)文章有新評(píng)論時(shí),發(fā)送郵件給管理員;
- 當(dāng)某個(gè)評(píng)論被回復(fù)時(shí),發(fā)送郵件給被回復(fù)用戶。
為了方便使用,我們在 emails.py
中分別為這兩個(gè)使用場景創(chuàng)建了特定的發(fā)信函數(shù),可以直接在視圖函數(shù)中調(diào)用。這些函數(shù)內(nèi)部則通過調(diào)用我們創(chuàng)建的通用發(fā)信函數(shù) send_mail()
來發(fā)送郵件。
from flask import url_for def send_mail(subject, to, html): ...
def send_new_comment_email(post): post_url = url_for('blog.show_post', post_id=post.id, _external=True) + '#comments' send_mail(subject='New comment', to=current_app.config['BLUELOG_EMAIL'], html='<p>New comment in post <i>%s</i>, click the link below to check:</p>' '<p><a href="%s" rel="external nofollow" rel="external nofollow" >%s</a></P>' '<p><small style="color: #868e96">Do not reply this email.</small></p>' % (post.title, post_url, post_url))
send_new_comment_email()
函數(shù)用來發(fā)送新評(píng)論提醒郵件。我們通過將 url_for()
函數(shù)的 _external
參數(shù)設(shè)為 True
來構(gòu)建外部鏈接。鏈接尾部的 #comments
是用來跳轉(zhuǎn)到頁面評(píng)論部分的URL片段(URL fragment
),comments
是評(píng)論部分 div
元素的 id
值。這個(gè)函數(shù)接收表示文章的 post
對象作為參數(shù),從而生成文章正文的標(biāo)題和鏈接。
URL 片段又稱片段標(biāo)識(shí)符(fragment identifier
),是 URL 中用來標(biāo)識(shí)頁面中資源位置的短字符,以 #
開頭,對于 HTML 頁面來說,一個(gè)典型的示例是文章頁面的評(píng)論區(qū)。假設(shè)評(píng)論區(qū)的 div
元素 id
為 comment
,如果我們訪問 http://example.com/post/7#comment
,頁面加載完成后將會(huì)直接跳到評(píng)論部分。
def send_new_reply_email(comment): post_url = url_for('blog.show_post', post_id=comment.post_id, _external=True) + '#comments' send_mail(subject='New reply', to=comment.email, html='<p>New reply for the comment you left in post <i>%s</i>, click the link below to check: </p>' '<p><a href="%s" rel="external nofollow" rel="external nofollow" >%s</a></p>' '<p><small style="color: #868e96">Do not reply this email.</small></p>' % (comment.post.title, post_url, post_url))
send_new_reply_email()
函數(shù)則用來發(fā)送新回復(fù)提醒郵件。這個(gè)發(fā)信函數(shù)接收 comment
對象作為參數(shù),用來構(gòu)建郵件正文,所屬文章的主鍵值通過 comment.post_id
屬性獲取,標(biāo)題則通過 comment.post.title
屬性獲取。
在 Bluelog 源碼中,我們沒有使用異步的方式發(fā)送郵件,如果你希望編寫一個(gè)異步發(fā)送郵件的通用發(fā)信函數(shù) send_mail()
,可以使用以下方式。
from threading import Thread from flask import current_app from flask_mail import Message from bluelog.extensions import mail def _send_async_mail(app, message): with app.app_context(): mail.send(message) def send_mail(subject, to, html): app = current_app._get_current_object() message = Message(subject, recipients=[to], html=html) thr = Thread(target=_send_async_mail, args=[app, message]) thr.start() return thr
需要注意的是,因?yàn)槲覀兊某绦驅(qū)嵗峭ㄟ^工廠函數(shù)構(gòu)建的,所以實(shí)例化 Thread
類時(shí),我們使用代理對象 current_app
作為 args
參數(shù)列表中 app
的值。另外,因?yàn)樵谛陆ǖ木€程時(shí)需要真正的程序?qū)ο髞韯?chuàng)建上下文,所以我們不能直接傳入 current_app
,而是傳入對 current_app
調(diào)用 _get_current_object()
方法獲取到的被代理的程序?qū)嵗?/p>
到此這篇關(guān)于Python個(gè)人博客程序開發(fā)實(shí)例框架設(shè)計(jì)的文章就介紹到這了,更多相關(guān)Python個(gè)人博客內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用Python的Supervisor進(jìn)行進(jìn)程監(jiān)控以及自動(dòng)啟動(dòng)
這篇文章主要介紹了使用Python的Supervisor進(jìn)行進(jìn)程監(jiān)控以及自動(dòng)啟動(dòng),使用python supervisor實(shí)現(xiàn),需要的朋友可以參考下2014-05-05解決Python訪問MySQL數(shù)據(jù)庫速度慢的問題
這篇文章主要介紹了解決Python訪問MySQL數(shù)據(jù)庫速度慢的問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-04-04Python實(shí)現(xiàn)免費(fèi)音樂下載器
本文主要為大家介紹了通過Python實(shí)現(xiàn)的免費(fèi)音樂下載器,文中的示例代碼講解詳細(xì),對我們的學(xué)習(xí)或工作有一定的幫助,需要的小伙伴可以學(xué)習(xí)一下2021-12-12使用Django框架中ORM系統(tǒng)實(shí)現(xiàn)對數(shù)據(jù)庫數(shù)據(jù)增刪改查
這篇文章主要介紹了使用Django的ORM實(shí)現(xiàn)對數(shù)據(jù)庫數(shù)據(jù)增刪改查方法,文中附含詳細(xì)示例代碼以及過程詳解,有需要的朋友可以借鑒參考下2021-09-09查看jupyter notebook每個(gè)單元格運(yùn)行時(shí)間實(shí)例
這篇文章主要介紹了查看jupyter notebook每個(gè)單元格運(yùn)行時(shí)間實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-04-04Python在信息學(xué)競賽中的運(yùn)用及Python的基本用法(詳解)
下面小編就為大家?guī)硪黄狿ython在信息學(xué)競賽中的運(yùn)用及Python的基本用法(詳解)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-08-08