目錄
前言 項目預覽 項目版本 項目構思 項目實戰 ? ? ?登錄子系統 ? ? ?后臺美化 完整項目獲取 尾言
前言
????當初是在2018年寫下的這篇文章,那時的django更新到了版本2.0,使用人數還是比較少的,網上的教程大多也很少。而現在隨著python web框架的流行,越來越多人開始接觸到了django這門技術。如今,django已經更新到了版本3.0,添加了支持異步等重要特性,但是這些特性和本篇文章基本無關。寫下這篇文章的初衷是為了讓剛接觸django框架的童鞋可以入門上手一個項目,了解如何快速搭建一個項目,畢竟python web的優勢便是快速易上手嘛【最近接觸了springboot后的感觸】。如今再次更新這篇博文(2020-2月),希望能夠給予大家入門一定的幫助。 ???? ???? p.s:其實建立一個web項目需要處理的事情比較雜,我就按照我的建立習慣給大家寫下這篇教程。 另外,本項目是我在重新寫時完整重新搭建,所以一定可以跑通,我會寫的比較仔細一點,如果你能耐心看完,必定有所收獲。 【-------------------------原創不易,請勿侵權------------------------------------------------------------------】
項目預覽
???? ????
項目版本
運行平臺:windows Python版本:3.7 Django版本:3.0 數據庫工具:sqlite 開發工具:Pycharm+vscode 依賴:pillow,django-simpleui,django_summernote ???? ????
項目構思
????個人博客系統屬于一個非常小型的項目,不會存在高并發的情況,同時注冊用戶主要也就是為了評論博客內容,其實用戶賬號安全性也可以完全不用考慮。項目采取前后端分離的形式進行開發,前后端信息交互多數采取ajax形式(按理說動態更新頁面比較友好交互,但是為了讓大家感受一下這兩種方式,在登錄這一塊采取靜態跳轉)。剩下的部分一次性在這里寫下來大家也不一定能看的很明白,在建立項目的過程中再給大家介紹。 ???? ????
項目實戰 請先下載靜態文件 下載連接:https://pan.baidu.com/s/1Er2S63MThOfzhlbuUkTEkw 之后替換相應的文件
我們首先給我們的項目起個名字:Ericam ???? (1)利用命令行創建項目。 ????
django
- admin startproject Ericam
???? (2)創建APP ???? 解釋一下:項目中會存在登錄子系統,博文管理子系統等,這些子系統每個都可以作為一個app,如此分離方便日后開發維護。但是作為一個入門項目,便不如此麻煩了。我們在整個項目只建立一個app。 由于我們準備搭建的是一個博客系統,所以就給這個APP起名為:blog ???? 在命令行下繼續輸入
python manage.py startapp blog
???? 此時文件目錄結構: ???? 介紹一下各個文件的用處 ???? 刪除test.py,新建一個urls.py文件 為什么需要兩個urls.py文件呢?方便分層管理,類似于一級目錄,二級目錄。 ???? ???? (3)注冊app并配置靜態文件目錄 ???? 在settings.py文件里添加如下內容 ????
STATICFILES_DIRS
= [ os
. path
. join
( BASE_DIR
, 'static' ) , ]
???? 【靜態文件:css,js和圖片文件等,我們在這里配置了文件目錄路徑】 此時運行項目,用瀏覽器訪問 http://127.0.0.1:8000/ 出現一個小火箭代表我們的項目搭建成功了。 ???? ???? (4) 新建文件夾,如下所示(建議直接將static文件夾復制過來,本博客不會講解css以及js): (所有html文件存放于templates文件夾下) 新建index_unlog.html文件【作為首頁,未登錄時顯示的頁面】 我們先簡單測試一下,給大家展示一下django如何通過view.py視圖層顯示html頁面。 在index_unlog.html里:
<!DOCTYPE html>
< html lang = " en" >
< head> < meta charset = " UTF-8" > < meta name = " viewport" content = " width=device-width, initial-scale=1.0" > < meta http-equiv = " X-UA-Compatible" content = " ie=edge" > < title> 首頁
</ title>
</ head>
< body> 個人博客系統測試
</ body>
</ html>
在views.py文件里:
def index_unlog ( request
) : return render
( request
, 'index_unlog.html' )
最后我們添加一下路由地址,在與settings.py同級目錄的urls.py:
urlpatterns
= [ path
( 'admin/' , admin
. site
. urls
) , path
( 'blog/' , include
( 'blog.urls' ) ) , path
( '' , views
. index_unlog
, name
= 'index_unlog' )
]
在新建的urls.py文件【以后我加個標號2代表該文件】里添加如下內容:
app_name = 'blog'
urlpatterns = [
]
ps:在pycharm里按alt+enter可以添加未引入的類包。 此時刷新項目,用瀏覽器訪問 http://127.0.0.1:8000/
搞懂了每個文件的大致作用,我們便可以開始正式開發博客系統啦。 我們按照模塊化進行開發。 ???? ???? ????
登錄子系統開發
(1)首頁(未登錄)-編寫index_unlog.html ????
{% load static %}
< html lang = " zh" > < head> < meta charset = " utf-8" > < meta name = " viewport" content = " width=device-width, initial-scale=1.0" > < meta name = " author" content = " Ericam_" > < title> Ericam_blog
</ title> < link rel = " shortcut icon" href = " {% static ' images/gt_favicon.png' %}" > < link rel = " stylesheet" media = " screen" href = " http://fonts.googleapis.com/css?family=Open+Sans:300,400,700" > < link rel = " stylesheet" href = " {% static ' css/bootstrap.min.css' %}" > < link rel = " stylesheet" href = " {% static ' css/font-awesome.min.css' %}" > < link rel = " stylesheet" href = " {% static ' css/bootstrap-theme.css' %}" > < link rel = " stylesheet" href = " {% static ' css/log.css' %}" > < link rel = " stylesheet" href = " {% static ' css/blog.css' %}" > </ head> < body class = " back" > < div class = " navbar navbar-inverse navbar-fixed-top headroom" > < div class = " container" > < div class = " navbar-header" > < button type = " button" class = " navbar-toggle" data-toggle = " collapse" data-target = " .navbar-collapse" > < span class = " icon-bar" > </ span> < span class = " icon-bar" > </ span> < span class = " icon-bar" > </ span> </ button> < a class = " navbar-brand" > < img src = " {%static ' css/images/lo.png' %}" alt = " Progressus HTML5 template" > </ a> </ div> < div class = " nav navbar-nav navbar-right" > </ div> </ div> </ div> < center> < div class = " container" style =" padding-top : 300px; min-height : 800px" > < div class = " row" > ,.
< p class = " lead" > <font color="white"">個人博客系統,盡情的享用吧(〃'▽'〃)
</ font> </ p> < p class = " tagline" > < font color = " white" > 如果您有優秀的建議,歡迎投遞哦
</ font> </ p> </ div> </ div> </ center> < footer id = " footer" class = " top-space" > < div class = " footer2" > < div class = " container" > < p class = " text-center" > Copyright
© 2020, Ericam_blog
</ p> </ div> </ div> </ footer>
</ body>
</ html>
第一句話{%load static%}代表引入靜態文件(css,js等) img,css,js等文件的引用與下述語句類似:
< link rel = " stylesheet" href = " {%static ' css/log.css' %}" >
此時打開瀏覽器查看效果: ???? ???? (2)登錄頁-login.html ????
{%load static%}
<!DOCTYPE html>
< html lang = " en" >
< head> < meta charset = " UTF-8" > < title> 登錄
</ title> < link rel = " shortcut icon" href = " {% static ' images/gt_favicon.png' %}" > < link rel = " stylesheet" href = " {%static ' css/log.css' %}" > < link rel = " stylesheet" href = " {%static ' css/semantic.css' %}" > < link rel = " stylesheet" href = " {% static ' css/font-awesome.min.css' %}" >
</ head>
< body class = " login" > < div class = " ui center aligned grid" style =" margin-top : 200px" > < div class = " ui six wide column" > < h1 class = " ui teal header" > Ericam blog-登錄
</ h1> < div class = " ui segment" > < div class = " ui content" > < form class = " ui large form" method = " post" action = " {%url ' login' %}" > < div class = " ui stacked segment" > < div class = " field" > < div class = " ui left icon input" > < input type = " text" name = " username" placeholder = " 請輸入用戶名" > </ div> </ div> < div class = " field" > < div class = " ui left icon input" > < input type = " password" name = " password" placeholder = " 請輸入密碼" > </ div> </ div> {{ error }}
< br> < a class = " pull-right field" > 忘記密碼
</ a> < button class = " ui fluid large teal button" type = " submit" > 登陸
</ button> </ div> < div class = " ui error message" > </ div> </ form> < div class = " ui message" > New to us?
< a> 注冊
</ a> </ div> </ div> </ div> </ div> </ div>
</ body>
</ html>
???? 添加路由信息: ????
urlpatterns
= [ path
( 'admin/' , admin
. site
. urls
) , path
( 'blog/' , include
( 'blog.urls' ) ) , path
( '' , views
. index_unlog
, name
= 'index_unlog' ) , path
( 'login' , views
. login
, name
= 'login' )
]
???? 添加視圖層views.py內容: ????
def login ( request
) : return render
( request
, 'login.html' )
???? 此時預覽: ???? ???? 在index_unlog.html里添加內容:
< a class = " btn" href = " {% url ' login' %}" > 登錄 / 注冊
</ a> </ li>
< p> < a class = " btn btn-action btn-lg" role = " button" href = " {% url ' login' %}" > START NOW
</ a> </ p>
???? 為了實現登錄功能,我們首先需要構造一個用戶表 ???? 打開models.py文件
from django
. db
import models
from django
. contrib
import admin
from django
. urls
import reverse
from django
. utils
. timezone
import now
class User ( models
. Model
) : username
= models
. CharField
( max_length
= 50 ) password
= models
. CharField
( max_length
= 200 ) nickname
= models
. CharField
( max_length
= 50 , default
= '匿名' ) email
= models
. EmailField
( ) created_time
= models
. CharField
( max_length
= 50 , default
= now
) comment_num
= models
. PositiveIntegerField
( verbose_name
= '評論數' , default
= 0 ) avatar
= models
. ImageField
( upload_to
= 'media' , default
= "media/default.png" ) def __str__ ( self
) : return self
. username
def comment ( self
) : self
. comment_num
+= 1 self
. save
( update_fields
= [ 'comment_num' ] ) def comment_del ( self
) : self
. comment_num
-= 1 self
. save
( update_fields
= [ 'comment_num' ] ) class UserAdmin ( admin
. ModelAdmin
) : list_display
= ( 'username' , 'email' )
然后打開命令行
python manage.py makemigrations
python manage.py migrate
這便生成了sqlite數據庫文件 通過sqliteStudio打開瀏覽: ???? 在views.py文件里編寫登錄邏輯
def login ( request
) : if request
. method
== 'POST' : user_name
= request
. POST
. get
( 'username' , '' ) pass_word
= request
. POST
. get
( 'password' , '' ) user
= User
. objects
. filter ( username
= user_name
) if user
: user
= User
. objects
. get
( username
= user_name
) if pass_word
== user
. password
: request
. session
[ 'IS_LOGIN' ] = True request
. session
[ 'nickname' ] = user
. nicknamerequest
. session
[ 'username' ] = user_name
return render
( request
, 'index.html' , { 'user' : user
} ) else : return render
( request
, 'login.html' , { 'error' : '密碼錯誤!' } ) else : return render
( request
, 'login.html' , { 'error' : '用戶名不存在!' } ) else : return render
( request
, 'login.html' )
因為我們需要記錄cookies,所以我們打開settings.py文件,注釋該語句 此時登錄功能已經實現了。登錄成功我們希望頁面進行跳轉,所以我們需要新建一個index.html
{% load static %}
< html lang = " zh" > < head> < meta charset = " utf-8" > < title> 首頁-Ericamblog
</ title> < meta name = " viewport" content = " width=device-width, initial-scale=1.0" > < meta name = " author" content = " Ericam_" > < link rel = " shortcut icon" href = " {% static ' images/gt_favicon.png' %}" > < link rel = " stylesheet" media = " screen" href = " http://fonts.googleapis.com/css?family=Open+Sans:300,400,700" > < link rel = " stylesheet" href = " {% static ' css/bootstrap.min.css' %}" > < link rel = " stylesheet" href = " {% static ' css/font-awesome.min.css' %}" > < link rel = " stylesheet" href = " {% static ' css/bootstrap-theme.css' %}" media = " screen" > < link rel = " stylesheet" href = " {% static ' css/blog.css' %}" > < link rel = " stylesheet" href = " {% static ' css/log.css' %}" >
</ head> < body class = " back" > <script src = "E:/bootstrap/bootstrap-3.3.7-dist/bootstrap-3.3.7-dist/js/jquery.min.js">
</ script> < div class = " navbar navbar-inverse navbar-fixed-top headroom" > < div class = " container" > < div class = " container-fluid" > < div class = " navbar-header" > < button type = " button" class = " navbar-toggle" data-toggle = " collapse" data-target = " .navbar-collapse" > < span class = " icon-bar" > </ span> < span class = " icon-bar" > </ span> < span class = " icon-bar" > </ span> </ button> < a class = " navbar-brand" > < img src = " {%static ' css/images/lo.png' %}" alt = " Progressus HTML5 template" > </ a> </ div> < ul class = " nav navbar-nav navbar-right" > < li> < a> < font size = " 4" color = " white" > {{user.nickname}}
</ font> </ a> </ li> < li> < a href = " {%url ' index_unlog' %}" > < i class = " fa fa-sighout" > </ i> < font size = " 4" > 注銷
</ font> </ a> </ li> </ ul> </ div> </ div>
</ div> < center> < div class = " container" style =" padding-top : 300px; min-height : 800px" > < div class = " row" > ,.
< p class = " lead" > <font color="white"">Easy-Download,這里有好多好多資源喔,盡情的享用吧(〃'▽'〃)
</ font> </ p> < p class = " tagline" > < font color = " white" > 如果您有優秀的資源,歡迎投遞哦
</ font> </ p> < p> < a class = " btn btn-action btn-lg" role = " button" href = " #" > START NOW
</ a> </ p> </ div> </ div> </ center> < footer id = " footer" class = " top-space" > < div class = " footer2" > < div class = " container" > < p class = " text-center" > Copyright
© 2020, Ericamblog
</ p> </ div> </ div> </ footer>
</ body>
</ html>
views.py
def logsuccess ( request
) : return render
( request
, 'index.html' )
添加路由信息
urlpatterns
= [ path
( 'admin/' , admin
. site
. urls
) , path
( 'blog/' , include
( 'blog.urls' ) ) , path
( '' , views
. index_unlog
, name
= 'index_unlog' ) , path
( 'login' , views
. login
, name
= 'login' ) , path
( '/log' , views
. logsuccess
, name
= 'login-success' )
]
手動在數據庫中添加一個用戶信息 我們進行預覽 ???? ???? 完成了登錄驗證功能后,我們就需要添加注冊功能,因為剛才用戶的信息是我們手動在數據庫內添加的,正常情況下應該是前端頁面將內容發送給后端,后端經過處理存儲在數據庫內。 ???? ???? 注冊模塊 ???? ???? (1)views.py
def register ( request
) : if request
. method
== 'POST' : user_name
= request
. POST
. get
( 'username' , '' ) pass_word_1
= request
. POST
. get
( 'password_1' , '' ) pass_word_2
= request
. POST
. get
( 'password_2' , '' ) nick_name
= request
. POST
. get
( 'nickname' , '' ) email
= request
. POST
. get
( 'email' , '' ) avatar
= request
. FILES
. get
( 'avatar' ) if User
. objects
. filter ( username
= user_name
) : return render
( request
, 'register.html' , { 'error' : '用戶已存在' } ) if ( pass_word_1
!= pass_word_2
) : return render
( request
, 'register.html' , { 'error' : '兩次密碼請輸入一致' } ) user
= User
( ) if avatar
: user
. avatar
= 'media/' + user_name
+ '.png' img
= Image
. open ( avatar
) size
= img
. size
print ( size
) r2
= min ( size
[ 0 ] , size
[ 1 ] ) if size
[ 0 ] != size
[ 1 ] : img
= img
. resize
( ( r2
, r2
) , Image
. ANTIALIAS
) r3
= int ( r2
/ 2 ) img_circle
= Image
. new
( 'RGBA' , ( r3
* 2 , r3
* 2 ) , ( 255 , 255 , 255 , 0 ) ) pima
= img
. load
( ) pimb
= img_circle
. load
( ) r
= float ( r2
/ 2 ) for i
in range ( r2
) : for j
in range ( r2
) : lx
= abs ( i
- r
) ly
= abs ( j
- r
) l
= ( pow ( lx
, 2 ) + pow ( ly
, 2 ) ) ** 0.5 if l
< r3
: pimb
[ i
- ( r
- r3
) , j
- ( r
- r3
) ] = pima
[ i
, j
] img_circle
. save
( 'blog/static/media/' + user_name
+ '.png' ) user
. username
= user_nameuser
. password
= pass_word_1user
. email
= emailuser
. nickname
= nick_nameuser
. save
( ) return render
( request
, 'index_unlog.html' ) else : return render
( request
, 'register.html' )
???? ???? 代碼含義很好理解,就是將前端提交的信息以user對象存儲到數據庫中,中間一部分代碼是將用戶提交的頭像切割成圓形(無需理解) ???? ???? (2)添加路由信息
urlpatterns
= [ path
( 'admin/' , admin
. site
. urls
) , path
( 'blog/' , include
( 'blog.urls' ) ) , path
( '' , views
. index_unlog
, name
= 'index_unlog' ) , path
( 'login' , views
. login
, name
= 'login' ) , path
( 'log' , views
. logsuccess
, name
= 'login-success' ) , path
( 'register' , views
. register
, name
= 'register' )
]
(3)添加register.html
{%load static%}
<!DOCTYPE html>
< html lang = " zh-hans" >
< head> < meta charset = " UTF-8" > < title> 注冊
</ title> < link rel = " shortcut icon" href = " {% static ' images/gt_favicon.png' %}" > < link rel = " stylesheet" href = " {%static ' css/log.css' %}" > < link rel = " stylesheet" href = " {%static ' css/semantic.css' %}" >
</ head>
< body class = " register" > < div class = " ui center aligned grid" style =" margin-top : 200px" > < div class = " ui six wide column" > < h1 class = " ui teal header" > < font color = " black" > EricamBlog-用戶注冊
</ font> </ h1> < div class = " ui segment" > < div class = " ui content" > < form class = " ui form" method = " post" action = " {%url ' register' %}" enctype = " multipart/form-data" > < div class = " field" > < input type = " text" name = " username" placeholder = " 請輸入用戶名" > < br> </ div> < div class = " field" > < input type = " password" name = " password_1" placeholder = " 請輸入密碼" > < br> </ div> < div class = " field" > < input type = " password" name = " password_2" placeholder = " 請確認密碼" > < br> </ div> < div class = " field" > < input type = " text" name = " nickname" placeholder = " 請輸入昵稱" > < br> </ div> < div class = " field" > < input type = " text" name = " email" placeholder = " 請輸入郵箱" > < br> </ div> < div> 頭像
< input type = " file" name = " avatar" > </ div> {{ error }}
< br> < button class = " ui fluid large teal button" type = " submit" > 注冊
</ button> </ form> </ div> </ div> </ div> </ div>
</ body>
</ html>
???? ???? 現在注冊模塊已經完成了,但是剛才我們在編寫登錄頁面時沒有添加對于注冊頁面的超鏈接跳轉,現在需要進行添加。 在login.html里修改如下內容: 此時注冊功能已經完成,大家可以自行測試。 ???? ???? 接下來我們再來添加忘記密碼模塊。 正常情況下,忘記密碼時應該發送郵件給郵箱,郵箱確認后再填寫新密碼。這里為了簡易操作,便忽略。 (1)添加views.py內容
def forget_password ( request
) : if request
. method
== 'POST' : user_name
= request
. POST
. get
( 'username' , '' ) email
= request
. POST
. get
( 'email' , '' ) user
= User
. objects
. filter ( username
= user_name
) if user
: user
= User
. objects
. get
( username
= user_name
) if ( user
. email
== email
) : request
. session
[ 'user_name' ] = user_name
return render
( request
, 'reset.html' ) else : return render
( request
, 'forget.html' , { 'error' : '您的用戶名和郵箱不匹配!' } ) else : return render
( request
, 'forget.html' , { 'error' : '請輸入正確的用戶名' } ) else : return render
( request
, 'forget.html' ) def reset ( request
) : if request
. method
== 'POST' : pass_word1
= request
. POST
. get
( 'password1' , '' ) pass_word2
= request
. POST
. get
( 'password2' , '' ) user_name
= request
. session
[ 'user_name' ] user
= User
. objects
. get
( username
= user_name
) if pass_word1
== pass_word2
: user
. password
= pass_word1user
. save
( ) return render
( request
, 'login.html' ) else : return render
( request
, 'reset.html' , { 'error' : '兩次密碼輸入不一致!' } ) else : return render
( request
, 'reset.html' )
(2)添加forget.html和reset.html forget.html
{%load static%}
<!DOCTYPE html>
< html lang = " en" >
< head> < meta charset = " UTF-8" > < title> 忘記密碼
</ title> < link rel = " stylesheet" href = " {%static ' css/log.css' %}" > < link rel = " stylesheet" href = " {%static ' css/semantic.css' %}" >
</ head>
< body class = " forget" > < div class = " ui center aligned grid" style =" margin-top : 200px" > < div class = " ui six wide column" > < h1 class = " ui teal header" > Ericam blog-忘記密碼
</ h1> < div class = " ui segment" > < div class = " ui content" > < form class = " ui form" method = " post" action = " {%url ' forget' %}" > < div class = " field" > < input type = " text" name = " username" placeholder = " 請輸入用戶名" > < br> </ div> < div class = " field" > < input type = " text" name = " email" placeholder = " 請輸入郵箱" > < br> </ div> {{ error }}
< br> < button class = " ui fluid large teal button" type = " submit" > 下一步
</ button> </ form> </ div> </ div> </ div> </ div>
</ body>
</ html>
???? ???? reset.html
{%load static%}
<!DOCTYPE html>
< html lang = " en" >
< head> < meta charset = " UTF-8" > < title> 重置密碼
</ title> < link rel = " shortcut icon" href = " {% static ' images/gt_favicon.png' %}" > < link rel = " stylesheet" href = " {%static ' css/semantic.css' %}" > < link rel = " stylesheet" href = " {%static ' css/log.css' %}" >
</ head>
< body class = " reset" > < div class = " ui center aligned grid" style =" margin-top : 200px" > < div class = " ui six wide column" > < h1 class = " ui teal header" > Ericam blog-重置密碼
</ h1> < div class = " ui segment" > < div class = " ui content" > < form class = " ui form" method = " post" action = " {%url ' reset' %}" > < div class = " field" > < input type = " password" name = " password1" placeholder = " 請輸入新密碼" > < br> </ div> < div class = " field" > < input type = " password" name = " password2" placeholder = " 請確認新密碼" > < br> </ div> {{ error }}
< br> < button class = " ui fluid large teal button" type = " submit" > 確認修改
</ button> </ form> </ div> </ div> </ div> </ div>
</ body>
</ html>
???? ???? (3)添加路由
urlpatterns
= [ path
( 'admin/' , admin
. site
. urls
) , path
( 'blog/' , include
( 'blog.urls' ) ) , path
( '' , views
. index_unlog
, name
= 'index_unlog' ) , path
( 'login' , views
. login
, name
= 'login' ) , path
( 'log' , views
. logsuccess
, name
= 'login-success' ) , path
( 'register' , views
. register
, name
= 'register' ) , path
( 'forget' , views
. forget_password
, name
= 'forget' ) , path
( 'reset' , views
. reset
, name
= 'reset' )
]
???? ???? 到了這里忘記密碼功能已經完成,最后我們還需要添加一下超鏈接跳轉 打開login.html文件,修改: ???? ???? 【至此,登錄子系統已經全部完成】
后臺美化
django默認自帶后臺管理系統 創建一個超級管理員賬戶:
python manage.py createsuperuser
訪問:http://127.0.0.1:8000/admin/ 接下來我們對后臺進行美化
pip install django-simpleui
pip install django_summernote
然后在settings.py添加:
INSTALLED_APPS
= [ "simpleui" , 'django.contrib.admin' , 'django.contrib.auth' , 'django.contrib.contenttypes' , 'django.contrib.sessions' , 'django.contrib.messages' , 'django.contrib.staticfiles' , 'blog' , 'django_summernote'
] SUMMERNOTE_CONFIG
= { 'iframe' : True , 'airMode' : False , 'styleWithSpan' : False , 'width' : '80%' , 'height' : '480' , 'lang' : 'zh-CN' ,
}
刷新,重新進入admin頁面: 給后臺添加注冊,方便管理數據內容: 修改admin.py文件
from django
. contrib
import admin
from blog
. models
import Article
, User
, Category
, Tag
, ArticleComment
, Message
from django_summernote
. admin
import SummernoteModelAdmin
class PostAdmin ( SummernoteModelAdmin
) : summernote_fields
= ( 'content' ) list_display
= [ 'article_id' , 'title' , 'created_time' ] search_fields
= [ 'title' ] list_filter
= [ 'created_time' ]
class CommentAdmin ( admin
. ModelAdmin
) : list_display
= [ 'username' , 'body' , 'title' ] search_fields
= [ 'title' ] admin
. site
. register
( Article
, PostAdmin
)
admin
. site
. register
( Category
)
admin
. site
. register
( Tag
)
admin
. site
. register
( User
)
admin
. site
. register
( ArticleComment
, CommentAdmin
)
修改models.py文件(完整版):
from django
. db
import models
from django
. contrib
import admin
from django
. urls
import reverse
from django
. utils
. timezone
import now
class User ( models
. Model
) : username
= models
. CharField
( max_length
= 50 ) password
= models
. CharField
( max_length
= 200 ) nickname
= models
. CharField
( max_length
= 50 , default
= '匿名' ) email
= models
. EmailField
( ) created_time
= models
. CharField
( max_length
= 50 , default
= now
) comment_num
= models
. PositiveIntegerField
( verbose_name
= '評論數' , default
= 0 ) avatar
= models
. ImageField
( upload_to
= 'media' , default
= "media/default.png" ) def __str__ ( self
) : return self
. username
def comment ( self
) : self
. comment_num
+= 1 self
. save
( update_fields
= [ 'comment_num' ] ) def comment_del ( self
) : self
. comment_num
-= 1 self
. save
( update_fields
= [ 'comment_num' ] )
class ArticleComment ( models
. Model
) : body
= models
. TextField
( ) username
= models
. CharField
( max_length
= 50 ) userimg
= models
. CharField
( max_length
= 70 ) nickname
= models
. CharField
( max_length
= 50 , default
= "匿名" ) createtime
= models
. DateTimeField
( verbose_name
= '創建時間' , default
= now
) article
= models
. CharField
( max_length
= 50 ) title
= models
. CharField
( max_length
= 50 ) def __str__ ( self
) : return self
. article
class Meta : ordering
= [ '-createtime' ] verbose_name
= '評論' verbose_name_plural
= '評論列表' db_table
= "comment" list_display
= ( 'article' , 'body' )
class Tag ( models
. Model
) : name
= models
. CharField
( verbose_name
= '標簽名' , max_length
= 64 ) def __str__ ( self
) : return self
. name
class Meta : ordering
= [ 'name' ] verbose_name
= '標簽名稱' verbose_name_plural
= '標簽列表' db_table
= "tag"
class Category ( models
. Model
) : name
= models
. CharField
( verbose_name
= '類別名稱' , max_length
= 64 ) class Meta : ordering
= [ 'name' ] verbose_name
= "類別名稱" verbose_name_plural
= '分類列表' db_table
= "category" def __str__ ( self
) : return self
. name
class Article ( models
. Model
) : STATUS_CHOICES
= ( ( 'd' , '草稿' ) , ( 'p' , '發表' ) , ) article_id
= models
. CharField
( verbose_name
= '標號' , max_length
= 100 ) title
= models
. CharField
( verbose_name
= '標題' , max_length
= 100 ) content
= models
. TextField
( verbose_name
= '正文' , blank
= True , null
= True ) status
= models
. CharField
( verbose_name
= '狀態' , max_length
= 1 , choices
= STATUS_CHOICES
, default
= 'p' ) views
= models
. PositiveIntegerField
( verbose_name
= '瀏覽量' , default
= 0 ) created_time
= models
. DateTimeField
( verbose_name
= '創建時間' , default
= now
) category
= models
. ForeignKey
( Category
, verbose_name
= '分類' , on_delete
= models
. CASCADE
, blank
= False , null
= False ) tags
= models
. ManyToManyField
( Tag
, verbose_name
= '標簽集合' , blank
= True ) def __str__ ( self
) : return self
. title
def viewed ( self
) : self
. views
+= 1 self
. save
( update_fields
= [ 'views' ] ) def next_article ( self
) : return Article
. objects
. filter ( id__gt
= self
. id , status
= 'p' , pub_time__isnull
= False ) . first
( ) def prev_article ( self
) : return Article
. objects
. filter ( id__lt
= self
. id , status
= 'p' , pub_time__isnull
= False ) . first
( ) class Meta : ordering
= [ '-created_time' ] verbose_name
= '文章' verbose_name_plural
= '文章列表' db_table
= 'article' get_latest_by
= 'created_time'
記得使用python manage.py migrate進行生成數據庫文件。 此時訪問后臺: 寫文章時富文本工具也加載了出來:
完整項目獲取
重構了代碼,同時更新了博客內容,關鍵難點已經寫下來了。 如果有問題歡迎在評論區提問。 如果想要獲取完整項目,請掃碼贊助該項目。 獲取方式:掃碼贊助9.9,留言郵箱地址。
尾言
其他子模塊和該模塊大同小異,暫時就不寫了。 其中評論提交和刪除采取的是ajax交互形式。 如果大家看了覺得有幫助請點贊,為了大家重新寫了這篇文章,同時重構了代碼,確保一定能跑通。
?
總結
以上是生活随笔 為你收集整理的django开发个人博客系统 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。