Python-Django实战 部署 安装  
创建项目 1 2 django-admin startproject blog  python manage.py runserver 
 
创建应用 1 python manage.py startapp article  
 
在blog/settings.py中INSTALLED_APPS字段中加入'article.apps.ArticalConfig'。
数据模型 添加数据模型 在article/models.py文件创建模型类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 from  django.db import  modelsclass  User (models.Model):    id =models.IntegerField(primary_key=True )      username=models.CharField(max_length=30 )      class  Article (models.Model):    content=models.TextField(verbose_name='内容' )     publish_date=models.DateTimeField()     user=models.ForeignKey(User,on_delete=models.CASCADE)      def  __repr__ (self ):         return  Article.title     def  short_content (self ):         return  self.content[:50 ]     short_content.short_description='content'   
 
数据库迁移 默认SQLite,如果要改为MySQL,需要修改blog\settings.py的DATABASES字段:
1 2 3 4 5 6 7 8 DATABASES={     'default' :{         'ENGINE' :'django.db.backends.mysql' ,         'NAME' :'xxx' ,          'USER' :'root' ,          'PASSWORD' :'root'       } } 
 
进入数据库:
 
创建库:
1 create  database xxx default  character  set  utf8;
 
安装MySQL驱动:
 
在blog\blog\__init__.py文件行首添加代码:
1 2 3 import  pymysqlpymysql.version_info(1 ,3 ,13 ,"final" ,0 ) pymysql.install_as_MySQLdb() 
 
创建数据表,生成迁移文件:
1 python manage.py makemigrations 
 
迁移数据库:
1 python manage.py migrate 
 
数据API 导入数据模型 进入命令行:
 
以下代码均在命令行中执行。
导入数据模型:
1 from  article.models import  User,Article
 
添加数据 1 2 3 4 5 6 user1=User.objects.create(id =1 ,username="andy" ,email="xxx" ) user2=User(id =2 ,username="zhangshan" ,email="xxx" ) user2.save() 
 
查询数据 1 2 3 4 5 6 7 8 9 10 11 12 13 users=User.objects.all () for  user in  users:    print (f'{user.id } ,{user.username} ' )      User.objects.first()  Person.objects.get(id =1 ) User.objects.filter (username__exact='andy' ) User.objects.filter (username__iexact='andy' )  User.objects.filter (id__gt=1 )  User.objects.filter (id__lt=100 )  User.objects.filter (username__contains='n' ).order_by('id' ) User.objects.filter (username__icontains='n' ) 
 
修改数据 1 2 3 user=User.objects.get(id =1 ) user.username='xxx'  user.save() 
 
删除数据 1 User.objects.get(id =1 ).delete() 
 
管理后台 创建管理后台 执行命令:
1 python manage.py createsuperuser 
 
在article/admin.py配置文件中创建后台控制模型类,并绑定到管理后台,添加以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 from  article import  User,Articleclass  UserAdmin (admin.ModelAdmin):    list_display=('username' ,'email' )      list_filter=('username' ,'email' )      search_fields=(['username' ,'email' ])  def  upper_case_name (obj ):    return  ("%s %s" %(obj.id ,obj.title)).upper() class  PubblishYearFilter (admin.SimpleListFilter):    title=_("发布年份" )      parameter_name='year'       def  lookups (self,request,model_admin ):         return (             ('2020' ,_('2020年' )),             ('2019' ,_('2019年' )),         )      def  queryset (self,request,queryset ):         if  self.value()=='2019' :             return  queryset.filter (publish_date__gte=date(2019 ,1 ,1 ),puslish_date__lte=date(2019 ,12 ,31 ))         if  self.value()=='2020' :             return  queryset.filter (publish_date__gte=date(2020 ,1 ,1 ),publish_date__lte=date(2020 ,12 ,31 )) class  ArticleAdmin (admin.ModelAdmin):    list_display=('title' ,'content' ,'publish_date' ,'short_content' )      list_display_link=('id' ,'title' )      list_editable=('title' ,'publish_date' )      list_filter=('title' ,PublishYearFilter)                list_display=(upper_case_name,)          list_display=('upper_case_name' ,)     def  upper_case_name (self,obj ):         return  ("%s %s" %(obj.id ,obj.title)).upper()     upper_case_name.short_description='Name'      list_filter=('title' ,'user__username' )      search_fields=('title' ,)     fields=(('id' ,'title' ),'content' ,'publish_date' )      fieldset=(         ('Main' ,{             'fields' :('id' ,'title' ,'publish_date' )          }),         ('Advance' ,{             'classes' :('collapse' ,),              'fields' :('content' ,),         })     ) admin.site.register(User,UserAdmin) admin.site.register(Article,ArticleAdmin) 
 
路由 格式转换类型 1 2 3 4 5 str 除/以外的非空字符 int 0和正整数 slug 字母数字-_ uuid  path 非空 包括路径分隔符 全集 
 
定义并创建路由 在blog/urls.py中添加:
1 2 3 4 5 6 7 8 9 10 11 12 13 from  django.urls import  re_path,includefrom  . import  viewsurlpatterns=[     path('admin/' ,admin.site.urls),     path('articles/' ,views.article_list),      path('articles/<int:year>/' ,views.year_archive),      path('articles/<int:year>/<int:month>/' ,views.month_archive),      path('articles/<int:year>/<int:month>/<slug:slug>/' ,views.article_detail)           re_path(r'^articles/(?P<year>[0-9]{4})/(?<month>[0-9]{2})/(?P<slug>[\w-]+)/$' ,views.article_detail)          path('articles/' ,include('article.urls' )) ] 
 
再创建views.py:
1 2 3 4 5 6 7 8 9 from  django.http import  HttpResponsedef  article_list (request ):    return  HttpResponse('xxx' ) def  year_archive (request,year ):    return  HttpResponse(f'{year} ' ) def  month_archive (request,year,month ):    return  HttpResponse(f'{year} ,{month} ' ) def  article_detail (request,year,month,slug ):    return  HttpResponse(f'{year} ,{month} ,{slug} ' ) 
 
如果使用上述include写法,需要新建article/urls.py :
1 2 3 4 5 6 from  django.urls import  pathfrom  . import  viewsurlpatterns=[     path('' ,views.article_list),     path('<int:year>/<int:month>/<slug:slug>/' ,views.article_detail) ] 
 
还要目录下新建views.py:
1 2 3 4 5 from  django.http import  HttpResponsedef  article_list (request ):    return  HttpResponse('xxx' ) def  article_details (request,year,month,slug ):    return  HttpResponse(f'{year} ,{month} ,{slug} ' ) 
 
视图 FBV 接上话使用include定义路由,并在article/urls.py 中添加:
1 2 3 urlpatterns=[     path('current' ,views.get_current_datetime) ] 
 
并在article/views.py中:
1 2 3 4 5 6 from  datetime import  datetimedef  get_current_datetime (request ):    today=datetime.today()     formatted_today=today.strftime("%Y-%m-%d" )     html=f"<html><body>今天是{formatted_today} </body></html>"      return  HttpResponse(html) 
 
CBV 1 2 3 4 5 6 from  django.views import  Viewclass  ArticleForm (View ):    def  get (self,request,*args,*kwargs ):         return  HttpResponse('xxx' )      def  post (self,request,*args,**kwargs ):         return  HttpResponse('xxx' )  
 
模板 创建并渲染 渲染模板:
1 2 3 4 5 from  django.shortcuts import  renderfrom  article.models import  Article,Userdef  article_list (request ):    articles=Article.objects.all ()     return  render(request,'article_list.html' ,{'article' :article}) 
 
新建目录blog\article\templates,新建base.html作为模板:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <!DOCTYPE html > <html  lang ="en" >     <head >          <meta  charset ="UTF-8" >          <title >              {% block title %}             {% endblock %}         </title >          {% load static %}         <link  rel ="stylesheet"  type ="text/css"  href ="{% static 'css/bootstrap.css' %}" >          <script  src ="{% static 'js/jquery.js' %}" > </script >          <script  src ="{% static 'js/bootstrap.js' %}" > </script >      </head >      <body  class ="container" >          <nav  class ="navbar navbar-expand-sm bg-primary navbar-dark" >                       </nav >          {% block content %}         {% endblock %}     </body >  </html > 
 
创建article_list.html作为子模板:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 {% extends "base.html" %} {% block tite %}     文章列表 {% endblock %} {% block content %}     <div  style ="margin-top:20px" >          <h3 > 文章列表</h3 >          <table  class ="table table-bordered" >              <thead >                  <tr >                      <th > 文章ID</th >                      <th > 作者</th >                      <th > 标题</th >                      <th > 发布时间</th >                  </tr >              </thead >              <tbody >                  {% for article in articles %}                     <tr >                          <td > {{article.id}}</td >                          <td > {{article.user.username}}</td >                          <td > {{article.title}}</td >                          <td > {{article.publish_date|date:'Y-m-d'}}</td >                      </tr >                  {% endfor %}             </tbody >          </table >      </div >  {% endblock %} 
 
其他过滤器:
1 2 3 4 5 6 7 {{value|default:"nothing"}} 指定默认值 {{value|length}} 列表或字符串长度 {{value|lower}} 变为小写字母 {{value|date}} 日期格式转换为字符串格式 {{value|safe}} 不转义 {{value|filesizeformat}} 人类可读文件大小 {{value|truncatewords:30}} 取固定长度 
 
表单 创建表单类,该类会呈现为HTML代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 from  django import  formsclass  LoginForm (forms.Form):    username=forms.CharField(         label='姓名' ,         required=True ,         min_length=3 ,         max_length=10 ,         widget=forms.TextInput(attrs={'class' :'form-control' }),         error_message={             'required' :'用户名不能为空' ,             'min_length' :'长度不能小于5个字符' ,             'max_length' :'长度不能超过10个字符' ,         }     )     email=forms.CharField(         label='邮箱' ,         required=True ,         max_length=50 ,         widget=forms.Textinput(attrs={'class' :'form-control' }),         error_message={             'required' :'邮箱不能为空' ,             'max_length' :'长度不能超过50个字符' ,         }     ) 
 
在article\urls.py中创建路由:
1 2 3 4 5 from  django.urls import  pathfrom  . import  viewsurlpatterns=[     path('login' ,views.LoginFormView.as_view()) ] 
 
在article\views.py中添加视图函数:
1 2 3 4 5 6 7 8 9 10 class  LoginFormView (View ):    def  get (self,request,*args,**kwargs ):         return  render(request,'login.html' ,{'form' :LoginForm()})     def  post (self,request,*args,**kwargs ):         form=LoginForm(request.POS              username=form.cleaned_data['username' ]             email=form.cleaned_data['email' ]             return  HttpResponse(f'{username} ,{email} ' )          else :             return  render(request,'login.html' ,{'form' :form})  
 
在article\templates下创建模板login.html文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 {% extends "base.html" %} {% block title %}     登录页面 {% endblock %} <style  type ="text/css" >     .errorlist {         color :red     } </style > <div  class ="container"  style ="margin-top:50px" >     <form  action =""  method ="post" >          {% csrf_token %}         <div  class ="form-group" >              <label > {{form.username.label}}</label >              {{form.username}}             {{form.username.errors}}         </div >          <div  class ="form-group" >              <label > {{form.email.label}}</label >              {{form.email}}             {{form.email.errors}}         </div >          <button  type ="submit"  class ="btn btn-primary" > 提交</button >      </form >  </div > {% endblock %} 
 
Session会话 启用 默认开启,删除方法:在settings.py中删除MIDDLEWARE中SessionMiddleware,从INSTALLED_APPS中删除django.contrib.sessions。
常用引擎 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 request.session['key' ]=123   request.session.setdefault('key' ,123 )  a=request.session['key' ]  a=request.session.get('key' ,None )  a=request.session.pop('key' )  del  request.session['key' ] request.session.delete("session_key" )  request.session.clear()  request.session.flush()  a=request.session.session_key  request.session.clear_expired()  a=request.session.exists('session_key' )  a=request.session.keys()  a=request.session.values()  a=request.session.items()  a=request.session.iterkeys()  a=request.session.itervalues()  a=request.session.iteritems()  request.session.set_expiry(value)  """ 	value参数说明: 		整数:这些秒数后失效 		datatime或timedelta:这个时间后失效 		0 关闭浏览器失效 		None 依赖全局失效策略 """ 
 
实现登录 进入shell:
 
创建用户:
1 2 from  django.contrib.auth.models import  UserUser.objects.create_user(username='andy' ,password='xxx' ) 
 
验证用户名和密码是否正确:
1 2 from  django.contrib.auth import  authenticateuser=authenticate(username='andy' ,password='xxx' )  
 
实现用户登录表单blog\article\forms.py:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class  LoginForm (forms.Form):    username=forms.CharField(         label='姓名' ,         required=True ,         min_length=3 ,         max_length=10 ,         widget=forms.TextInput(attrs={             'class' :'form-control' ,             'placeholder' :"请输入用户名"          }),         error_message={             'required' :'用户名不能为空' ,             'min_length' :'长度不能小于3个字符' ,             'max_length' :'长度不能超过10个字符' ,         }     )     password=forms.CharField(         label='密码' ,         required=True ,         min_length=6 ,         max_length=50 ,         widget=forms.passwordInput(attrs={             'class' :'form-control mb-0' ,             'placeholder' :"请输入密码"          }),         error_message={             'required' :'用户名不能为空' ,             'min_length' :'长度不能少于6个字符' ,             'max_length' :'长度不能超过50个字符' ,         }     ) 
 
修改路由,略。
打开blog\article\views.py,添加代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from  django.contrib.auth import  authenticate,loginfrom  django.contrib import  messagesfrom  django.http import  HttpResponseRedirectclass  LoginFormView (View ):    def  post (self,request,*args,**kwargs ):         form=LoginForm(request.POST)         if  form.is_valid():             username=form.cleaned_data['username' ]             password=form.cleaned_data['password' ]             user=authenticate(request,username=username,password=password)             if  user is  not  None :                 login(request,user)                 return  HttpResponseRedirect('/articles' )             else :                 message.add_message(request,messages.WARNING,'用户名和密码不匹配' )         return  render(request,'login.html' ,{'form' :form}) 
 
模板文件blog\article\templates\login.html:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <div  class ="container"  style ="margin-top:50px" >     {% if messages %}         {% for message in messages %}             <div  class ="alert alert-{{message.tags}} alert-dismissible fade show"  role ="alert" >                  <strong > {{message}}</strong >                  <button  type ="button"  class ="close"  data-dismiss ="alert"  aria-label ="Close" >                      <span  aria-hidden ="true" > × </span >                  </button >              </div >          {% endfor %}     {% endif %}     <form  action =""  method ="post" >          {% csrf_token %}         <div  class ="form-group" >              <label > {{form.username.label}}:</label >              {{form.username}}             {{form.username.errors}}         </div >          <div  class ="form-group" >              <label > {{form.password.label}}</label >              {{form.password}}             {{form.password.errors}}         </div >          <button  type ="submit"  class ="btn btn-primary" > 提交</button >      </form >  </div > 
 
退出登录,创建路由:
1 2 3 urlpatterns=[     path('logout' ,view.logout), ] 
 
在blog\article\views.py中创建logout函数:
1 2 3 4 from  django.contrib.auth import  authenticate,login,logout as  django_logoutdef  logout (request ):    django_logout(request)     return  HttpResponseRedirect('/login' ) 
 
验证用户是否登录,如果登录,则可以访问article:
1 2 3 4 5 from  django.contrib.auth.decorators import  login_required@login_required def  article_list (request ):    articles=Article.objects.all ()     return  render(request,'article_list.html' {'article' :articles}) 
 
如果没有登录,会跳转到404,可在blog\blog\settings.py中设置跳转路径:
1 LOGIN_URL='/articles/login'