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'