Django框架使用
1、Django框架简介与环境搭建
##Django是python写的重量级开源web框架,它组件丰富、向用户提供完整的开发文档,使用Django可以用少量的代码就能完成一个网站的大部分内容,极大的提高了开发效率。
##Django基于MVC模型(模型+视图+控制器)设计,该模型应用使Django项目的修改、拓展和代码复用变得更加方便和容易,同时Django还强调快速开发和DRY原则(Do Not Repeat Youself),而基于MVC框架Django有一个自己的名字MVT。
1.1 MVC框架简介
MVC框架的运行流程,以用户登录为例,它有这么几个步骤:
当用户点击注册时,用户名密码被提交到服务器;由控制器C去接收页面提交的数据;再由M将用户名和密码保存进数据库,然后数据库返回保存结果,并将结果传回给控制器C,然后通过V产生html页面,再由C将页面返回给浏览器。
- M: Model模型, 和数据库进行交互。
- V: View视图,用于处理业务逻辑,产生html页面或数据(Django中为T)。
- C: Controller控制器,接受请求,进行处理,并与M和V交互,返回应答(Django中为V)。
1.2 Django项目和应用创建
安装Django环境:
pip install django或pip install django==版本号创建项目:
django-admin startproject 项目名项目目录结构(以test1项目为例):

- test1: 项目管理目录,在项目目录下,与项目目录同名
- __ init__.py: 说明test1目录是一个python包
- settings.py: 项目配置文件
- urls.py: 用于url路由的配置
- wsgi.py:服务器和Django项目交互入口
- manage.py: 项目管理文件,在项目目录下
- test1: 项目管理目录,在项目目录下,与项目目录同名
创建应用(先要进入到项目中)
python manage.py startapp 应用名此处创建的应用为booktest。
一个项目通常由多个不同的功能模块组成,在Django中每个功能模块用一个Django应用来开发,每一个应用完成一个特定的功能,所以在开发之前先要进行功能模块的划分。
应用目录结构:

- __init__.py: 说明booktest目录是一个python模块
- models.py: 用于写和数据库相关的内容
- views.py: 接受请求,处理请求,与M和T进行交互,返回应答,在该文件中定义**视图函数**
- tests.py: 用于写测试代码
- admin.py: 用于网站后台管理
- apps.py: 表示当前应用
- 目录migrations: 存放迁移文件
至此,项目和应用都已创建,但是要开发这个应用。还需要建立项目与应用之间的关系,即注册该应用。
建立项目和应用之间的关系(注册应用)
注册应用要在项目配置文件settings.py的INSTALLED_APPS中加入刚刚创建的应用名称。

在INSTALLED_APPS项中加入刚刚创建的应用名称:INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'booktest' # 注册应用 ]启动项目,看项目有没有创建成功
# 注意要先进入项目中,默认8000端口 python manage.py runserver # 如果提示端口被占用,换个端口 python manage.py runserver 127.0.0.1:8001
在浏览器地址栏中输入127.0.0.1:8000(此处写你自己定义的端口号)如果出现以下,说明项目创建成功。
2、Django的基本使用
2.1 ORM框架介绍
ORM(对象关系映射),它的作用是建立对象与关系型数据库表之间的映射,通过类和对象操作对应的数据表,避免了写复杂的SQL语句;ORM另一个作用是根据模型类迁移生成对应的数据表。Django中内置了ORM框架,在应用下的models.py文件中设计模型类。
定义模型类
# 在booktest(应用)下的models.py文件中 from django.db import models # Create your models here. # 设计和表对应的类 # 定义图书类(一类) class BookInfo(models.Model): """图书模型类""" # id会自动生成 # 字段名称,书名 book_title = models.CharField(max_length=20) # 出版日期 public_date = models.DateField()我们的目的是根据这个定义的模型类,生成数据库中对应的表,在Django中生成模型类对应的表两步走:
进入项目中,在终端执行迁移:
# 第一步 生成迁移文件 python manage.py makemigrations # 第二步 执行迁移生成表 python manage.py migrate
得到以下结果说明迁移成功:
迁移成功之后我们在pycharm右侧数据库中可以看到已成功生成数据库:
表中字段名称和模型类中的字段名称是一致的,表名格式是: 应用名_模型类名。注意Django默认数据库是sqlite3数据库,可以在项目配置文件settings.py中修改DATABASES配置项,将数据库换成mysql或其他。
2.2 通过模型类去操作数据表
先进入项目shell:
python manage.py shell
以下操作在终端中执行:
# 导入模型类
In [1]: from booktest.models import BookInfo
# 实例化模型类
In [2]: b = BookInfo()
"""添加数据"""
# 添加书名
In [3]: b.book_title = "水浒传"
# 导入日期模块
In [4]: from datetime import date
# 添加出版日期
In [5]: b.public_date = date(2000,1,1)
# 存入数据库
In [6]: b.save()
"""查询数据"""
# 模型类.objects.get(条件)
In [7]: book_sh = BookInfo.objects.get(id=1)
In [10]: book_sh.book_title
Out[10]: '水浒传'
In [11]: book_sh.public_date
Out[11]: datetime.date(2000, 1, 1)
"""修改数据"""
In [12]: book_sh.public_date = date(2001,1,1)
# 要保存一下,才能修改成功
In [13]: book_sh.save()
In [14]: book_sh.public_date
Out[14]: datetime.date(2001, 1, 1) # 可以看到出版日期已修改
"""删除"""
In [15]: book_sh.delete()
"""退出终端"""
In [16]: quit()
Django模型常用字段与属性:
| 字段名称 | 字段描述 |
|---|---|
| CharField | 字符串类型,必须设置max_length |
| IntergerField | 整数类型,可设置默认值default |
| FloatField | 小数类型,可设置默认值default, 其他参数同下 |
| DecimalField | 小数类型,参数max_digit表示总位,参数decimal_places表示位数 |
| EmailField | 邮箱格式字符串 |
| TextField | 文本类型 |
| DateField | 日期类型 , 参数auto_now_add=True表示创建时间,不需要给他传参数 |
| FileField | 文件类型,可以保存文件路径,同时自动上传文件,必须设置upload_to上传到媒体路径下的位置 |
| ImageField | 图片文件类型,可以保存文件路径,同时自动上传文件,必须设置upload_to上传到媒体路径下的位置 |
| - | - |
| 属性名称 | 属性描述 |
| default | 设置默认值 |
| primary_key | 值为True,则该字段是主键,默认False |
| unique | True,表示这个字段在表中只能出现一次,默认False |
| db_index | True,则会在表中为此字段建立索引,默认False |
| db_columen | 指定字段名称, 默认使类属性名称 |
| null | True,表示允许为空,默认为False。数据库的范畴 |
| blank | True,表示允许在后台管理添加数据时不填,默认为False |
2.3 模型类一对多关系建立及关系查询
建立图书类与英雄类之间一对多关系
# 定义图书类(一类) class BookInfo(models.Model): """图书模型类""" # id会自动生成 # 字段名称,书名 book_title = models.CharField(max_length=20) # 出版日期 public_date = models.DateField() # 英雄人物类(多类) # 英雄名 性别 年龄 备注 # 图书类与英雄人物类之间是一对多关系 class HeroInfo(models.Model): """英雄人物类""" # 英雄名 hero_name = models.CharField(max_length=20) # 性别 BooleanField为布尔值, 默认False(男性) hero_gender = models.BooleanField(default=False) # 备注 hero_demo = models.CharField(max_length=128) # 年龄 hero_age = models.IntegerField() # 外键 图书类与英雄类之间的一对多关系,多表中有一个外键 """多类中定义关系属性""" hero_book = models.ForeignKey(to='BookInfo', on_delete=models.CASCADE)定义完模型类,再次执行迁移,会在数据库中看到以下结果:

一对多关系操作
以下操作在shell中执行:python manage.py shell进入shell"""一对多基本操作""" # 导入模型类 In [1]: from booktest.models import BookInfo, HeroInfo # 实例化一个图书模型类 In [2]: b = BookInfo() # 导入日期函数 In [3]: from datetime import date # 实例化英雄模型类 In [4]: h = HeroInfo() # 添加一个英雄的信息 In [5]: h.hero_name = "林冲" In [6]: h.hero_gender = False In [7]: h.hero_age = 10 In [8]: h.hero_demo = "豹子头林冲" # 取出水浒传(id=1) In [9]: book_sh = BookInfo.objects.get(id=1) """关联""" # 关联英雄类与图书类 In [10]: h.hero_book = book_sh # 保存 In [11]: h.save() """一查多""" # 查询一本书中所有的英雄(一查多: 一.多类名小写_set.all()) # 得到的结果是对象集合 In [12]: book_sh.heroinfo_set.all() Out[12]: <QuerySet [<HeroInfo: HeroInfo object (1)>]>
查询函数:
通过 模型类.objects 属性可以调用如下函数,实现模型类对数据表 的快速操作
| 函数名 | 功能 | 返回值 | 说明 |
|---|---|---|---|
| get | 返回表中满足条件的一条且只能有一条数据 | 模型类对象 | 查询到多条会抛出异常 |
| all | 返回表中满足条件的所有数据 | QuerySet | 返回值称作查询集 |
| filter | 返回满足条件的数据 | QuerySet | filter查询方法 |
| exclude | 返回不满足条件的数据 | QuerySet | 和filter用法一致,只是返回的数据和filter返回的数据相反 |
| order_by | 对查询结果进行排序 | QuerySet | 参数中写根据哪些条件进行排序 |
| Q对象 | 用于查询条件之间的逻辑关系,not and or,可以对Q对象进行& ~ | QuerySet | 使用之前需要先导入form django.db.models import F 使用方法 |
| F对象 | 用于属性之间的比较 | QuerySet | 使用之前需要先导入form django.db.models import Q |
| 除上述用法之外,还有聚合函数。而QuerySet(得到的结果)还可以继续调用上述方法。query.exists()可以查询查询集是否为空,False为空。 |
2.4 Django后台管理
后台管理的作用: 帮助我们管理数据表
Django提供了强大的后台管理功能,由应用下的admin.py管理。使用它需要执行以下步骤:
本地化
- 语言和时区本地化 - 修改项目配置文件settings.py中的语言和时区项 - `LANGUAGE_CODE = 'zh-hans'` - `TIME_ZONE = 'Asia/Shanghai'`创建管理员账户
python manage.py createsuperuser
登录后台管理页面:
- 先启动Django项目:
python manage.py runserver - 进入后台管理界面:
http://127.0.0.1:8000/admin - 进去之后啥也没有,这时候就需要对模型类进行注册
- 先启动Django项目:
注册模型类
在应用下的admin.py中注册模型类,告诉Django框架根据注册的模型类来生成对应的管理界面。
from django.contrib import admin # 导入图书模型类(其它模型类的注册方法也是一样的) from .models import BookInfo # Register your models here. # 注册图书模型类 admin.site.register(BookInfo)注册完显示以下界面:

注册完可以在Django后台管理数据表,对表中的数据进行增删改查。自定义Django后台管理页面
虽然已经将模型类注册,但是进去发现显示的信息不是我们想要的,此时就需要自定义模型管理类,来美化Django后台管理页面。class BookInfoAdmin(admin.ModelAdmin): """自定义图书模型管理类""" # 定义要显示的字段列表 list_display = ['id', 'book_title', 'public_date'] # 注册图书模型类,将自定义的模型管理类也传入register admin.site.register(BookInfo, BookInfoAdmin) """其他模型类的注册方式也是一样的"""
写完之后,刷新后台管理页面,发现定义的字段已经显示出来了:
2.5 视图函数的使用
在Django中,通过浏览器去请求一个页面时,是使用视图函数来处理这个请求的,视图函数处理之后,要给浏览器返回页面内容。
定义视图函数
视图函数定义在应用下的views.py中,此时我们只有一个应用那么就在booktest应用目录下的views.py中定义视图函数,视图函数就是python中普通的函数,定义一个index视图函数当用户输入http://127.0.0.1:8000/index显示Hello, Django!:from django.shortcuts import render from django.http import HttpResponse # Create your views here. # 第一步定义视图函数 # 第二步进行url配置,目的是建立url地址和视图之间的关系 def index(request): """用户输入http://127.0.0.1:8000/index显示""" # 此处写处理,与M和T进行交互 # 最终需要返回一个HttpResponse对象 return HttpResponse("Hello, Django!")为了让Django知道URl对应的视图函数是这个视图函数,还需要进行URL配置。
配置URL
首先在应用目录下面(此处是booktest)新建一个urls.py;然后在项目管理目录下的urls.py中加配置项:"""项目管理目录下的urls.py中""" from django.conf.urls import url from django.contrib import admin from django.urls import path, include # 项目的urls文件 urlpatterns = [ path('admin/', admin.site.urls), # 配置项 url(r'^', include('booktest.urls')), # 包含刚刚创建的应用booktest里面的urls文件 ]然后回到刚刚新建的应用目录下面(此处是booktest)的urls.py中,通过URL函数建立视图函数和路由之间的关系:
"""应用目录下面(此处是booktest)的urls.py""" from django.conf.urls import url from . import views urlpatterns = [ # 通过url函数设置url路由的配置项 url(r'^index', views.index), # 建立index视图和index路由之间的关系 ]访问http://127.0.0.1:8000/index,成功显示:

当我们通过浏览器输入一个地址时,Django拿到的是去除域名后的这部分(/不参与匹配),它会拿这一部分先到项目的urls.py中进行查找,也就是和urlpatterns中的路由配置项正则表达式进行匹配; 匹配成功就执行include里面的动作,然后找到应用中的urls.py, 继续和URL函数设置的路由配置项进行匹配,匹配成功就执行该配置项中的视图函数,然后再由视图函数返回HttpResponse,渲染到页面就是我们看到的内容。
为了让HttpResponse返回一个标准的html页面,就需要使用模板。
2.6 模板文件的使用
在上面的例子中,我们返回了一个字符串,要返回一个标准的HTML页面,就需要使用模板。Django中的模板不仅仅可以返回HTML文件,也可以返回变量,甚至是代码。
创建模板目录templates
在项目目录下新建一个模板文件夹,以后所有的模板文件将放入这个文件夹:
建好模板目录之后,需要配置模板目录。配置模板目录
在项目管理目录下的项目管理文件settings.py中,修改TEMPLATES项下的DIRSTEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', # BASE_DIR是项目所在绝对路径 'DIRS': [os.path.join(BASE_DIR, 'templates')], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ]使用模板文件
Django中使用模板文件有四步:- 加载模板文件
- 定义模板上下文,给模板文件传递数据
- 模板渲染,产生标准的HTML内容
- 给浏览器返回一个HttpRequest对象
Django内部提供了一个render方法,使用时直接调用即可。
重新定义模板文件(在应用下的views.py中):from django.shortcuts import render from django.http import HttpResponse # Create your views here. # 第一步定义视图函数 # 第二步进行url配置,目的是建立url地址和视图之间的关系 # def index(request): # """用户输入http://127.0.0.1:8000/index显示""" # return HttpResponse("Hello, Django!") def index(request): """用户输入http://127.0.0.1:8000/index显示""" # return HttpResponse("Hello, Django!") return render(request, 'booktest/index.html', {'content': "Hello, Django!"})渲染模板
根据你使用的数据,替换页面上的显示的数据:<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>模板文件</title> </head> <body> <h3>这是一个模板文件</h3> <h4>这是渲染过来的的数据:</h4> /*jinjia2渲染模板*/ <p>{{ content }}</p> </body> </html>刷新页面显示:

3、Django 后端配置、重定向、模型进阶(M)
**回顾:**
- 1.创建Django项目:django-admin startproject 项目名称
- 2.**进入项目**创建应用: python manage.py startapp 应用名称
- 3.在项目配置文件 settings.py中 注册app: 将app名加入到INSTALLED_APPS项中
- 4.本地化项目: 在 项目配置文件settings.py中 修改 LANGUAGE_CODE 与 TIME_ZONE
- 5.启动项目: python manage.py runserver
- 完成以上步骤,就可以进行基本开发了
多数时候,我们SQLITE数据库不能满足开发需要,通常我们使用MySQL数据库进行开发,那就需要配置MySQL数据库。
3.1 Django配置MySQL数据库
"""在项目配置文件settings.py中"""
DATABASES = {
'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
'ENGINE': 'django.db.backends.mysql',
# 'NAME': BASE_DIR / 'db.sqlite3',
'NAME': 'test', # mysql数据库名,注意这个数据库必须手动建好,否则报错
'USER': 'root', # mysql用户名
'PASSWORD': 'root', # 用户名对应的密码
'HOST': 'localhost', # 指定mysql地址,此处是本地
'PORT': 3306 # 端口号
}
}
然后启动项目,可能会出现以下错误:
django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module.
Did you install mysqlclient?
这时候按Ctrl+C退出,在应用下的__init__.py中添加下面两句:
"""应用下的__init__.py中"""
# 未安装pymysql,先安装pymysql
import pymysql
pymysql.install_as_MySQLdb()
重新启动项目,启动成功!
3.2 重定向
Django中的重定向: 当视图函数处理完成一个逻辑后,不需要向浏览器呈现数据,而是转回到其它页面(可以理解为调用其它的视图函数),给出一个大佬的博客Django重定向的几种方法。
3.3 模型进阶
模型类关系
一对多关系
models.ForeignKey()定义在多的类中
比如图书模型类与英雄模型类:# to参数为一类类名 hero_book = models.ForeignKey(to='BookInfo', on_delete=models.CASCADE)多对多关系
models.ManyToManyField()定义在哪个类中都可以
比如新闻模型类与新闻类型模型类:# 新闻类型类 class NewsType(models.Model): # 新闻类型名 type_name = models.CharField(max_length=20) """关系属性,也可以定义在新闻模型类中""" type_news = models.ManyToManyField(to='NewsInfo') # 新闻类 class NewsInfo(models.Model): # 新闻标题 news_title = models.CharField(max_length=128) # 发布时间 news_date = models.DateField(auto_now_add=True) # 信息内容 news_content = models.TextField()一对一关系
models.OneToOneField()定义在哪个类中都可以
比如员工基本信息类与员工详细信息类,员工工号唯一# 员工基本信息类 class EmployeeBasicInfo(models.Model): employ_name = models.CharField(max_length=20) employ_age = models.IntegerField() employ_gender = models.BooleanField(default=False) """关系属性,也可以定义在员工详细信息模型类中""" detail_employ = models.OneToOneField(to='EmployeeDetailInfo', on_delete=models.CASCADE) # 员工详细信息类 class EmployeeDetailInfo(models.Model): employ_addr = models.CharField(max_length=256) employ_tel = models.CharField(max_length=20)
一对多关联查询(通过模型类实现)
在一对多关系中,一对应的类叫做一类,多对应的类叫做多类,我们把类中建立模型类与模型类关联的属性叫做关系属性。
通过对象查询的方法:由一类的对象查询多类的时候:
一类的对象.多类名小写_set.all()由多类的对象查询一类的时候:
多类的对象.关联属性由多类的对象查询一类对象的id的时候:
多类的对象.关联属性_id
通过模型类实现关联查询的方法:
通过多类的条件查询一类的数据:
一类名.objects.filter(多类名小写__多类属性名__条件名)通过一类的条件查询多类的数据:
多类名.objects.filter(关联属性__一类属性名__条件名)
例1:查询id为1的图书关联的英雄的信息:
原来的查询方法(根据对象去查询):
# 先查询id为1的图书 b = BookInfo.objects.get(id=1) # 再用这个[书]去查询它里面的英雄 b.heroinfo__set.all()通过模型类查询
# 通过一类的条件查询多类的数据 HeroInfo.objects.filter(hero_book__id=1)
例2:查询id为1的英雄关联的图书的信息:
原来的查询方法(根据对象去查询)
# 先查询id为1的英雄 h = HeroInfo.objects.get(id=1) # 然后再用这个[英雄]去查和他相关的那本书 # hero_book是关系属性名 h_book =h.hero_book通过模型类查询
# 通过多类的条件查询一类的数据 # 一类名.objects.filter(多类名小写__多类属性名__条件名) BookInfo.objects.filter(heroinfo__id=1)
例3:查询图书信息,要求图书中英雄的描述包含’八’:
- 通过模型类查询
# 通过多类的条件查询一类的数据 # 一类名.objects.filter(多类名小写__多类属性名__条件名) BookInfo.objects.filter(heroinfo__hero_dmeo__contains='八')
例4:查询图书信息,要求图书中的英雄的id大于3:
通过模型类查询
# 通过多类的条件查询一类的数据 # 一类名.objects.filter(多类名小写__多类属性名__条件名) BookInfo.objects.filter(heroinfo__id__gt=3)
例5:查询书名为天龙八部的所有英雄:
通过模型类查询
# 通过一类的条件查询多类的数据 # 多类名.objects.filter(关联属性__一类属性名__条件名) HeroInfo.objects.filter(hero_book__book_title='天龙八部')
模型-自关联
所谓的自关联是一种特殊的一对多关系,只是这种一对多关系对用的数据都在一张表里。
以地区自关联模型为例(最终结果是做一个显示徐州上下级地区的功能):定义地区模型类
# 地区模型类 class AreaInfo(models.Model): # 地区名称 area_title = models.CharField(max_length=128) # 关系属性,代表当前地区的父级地区,null表示可以为空,self参数表示自关联 area_parent = models.ForeignKey('self', null=True, blank=True, on_delete=models.CASCADE)注册模型类
"""在应用下的admin.py中""" # 注册地区模型类 admin.site.register(AreaInfo)迁移生成数据库
# 生成迁移文件 python manage.py makemigrations # 执行迁移 python manage.py migrate向表中添加数据

定义视图函数
"""在应用下的views.py中""" def areas(request): """获取徐州市的上几地区和下级地区""" # 获取徐州市的信息 area = AreaInfo.objects.get(area_title='徐州市') # 查询徐州市的上级地区 parent = area.area_parent # 查询江苏省的下级地区 children = area.areainfo_set.all() # 使用模板 return render(request, 'booktest/areas.html', {'area':area, 'parent':parent, 'children':children})配置路由
"""在应用下的urls.py中""" from django.conf.urls import url from . import views urlpatterns = [ url(r'^index', views.index), url(r'^areas', views.areas) # 显示地区 ]在地址栏输入
http://127.0.0.1:8000/areas
模型_管理器
在查询的时候,BookInfo.objetcs.all()中的objects是什么呢?其实它是Django帮我们给每一个模型类自动生成的管理器对象,通过这个管理器可以实现对数据的查询。
objects是models.Manger类的一个对象。当我们自定义管理器之后,Django不再帮我们生成默认的objects管理器。自定义管理器步骤
- 自定义一个管理器类,这个类继承models.Manger类
- 再在具体的模型类里定义一个自定义管理器对象
自定义管理器类的应用场景:
- 改变查询的结果集:比如将BookInfo.objects.all()让它返回没有删除的的图书的数据。
- 添加额外的方法:管理器中定义一方法帮我们操作模型类对应的数据表。
不过一般情况下,我们也不去修改这个东西,如果需要自定义管理器请参照Django开发文档(我的电脑不知道为什么进不了Django官网,在此就不放链接了)。
模型元选项_指定模型类对应的表名
当我们指定了模型类对应的表名之后,就可以随意修改应用名而不使程序因为修改应用名发生错误了。
方法: 在模型类中再定义一个Meta类,然后将Meta类的类属性db_table = 指定的表名即可。
以图书类为例:# Create your models here. # 建立图书模型类, 一类 class BookInfo(models.Model): book_title = models.CharField(max_length=20) public_date = models.DateField() book_read = models.IntegerField(default=0) book_comment = models.IntegerField(default=0) # 逻辑删除标记(软删除) is_delete = models.BooleanField(default=False) class Meta: """将图书模型类对应的表名指定为bookinfo""" db_table = 'bookinfo' def __str__(self): return self.book_title
4、视图进阶
4.1 回顾
视图的功能
视图的功能:接受请求,进行处理,与M和T交互,返回应答。
返回应答是html:render,也可能是重定向:redirect,还可能是JsonResponse。视图函数的使用
定义视图函数
视图函数就是一个普通的函数,必须要有request参数。这个request参数是一个HttpRequest类型的对象,参数名可以变化,但是不建议更改。配置url
目的是建立url和视图函数之间的对应关系。定义模板文件
有模板文件就在templates下面配置html文件
url配置的过程
- 在项目的urls文件中包含具体应用的urls文件,在具体应用的urls文件中包含具体url和视图的对应关系。
- url配置项是定义在一个名叫urlpatterns的列表中,其中的每一个元素就是一个配置项,每一个配置项都调用url函数。

4.2 视图进阶
视图_错误视图
当用户输入一个你的网站不存在的地址时,会显示Page not found(404)和项目url配置信息,这样url配置信息将会全部暴露给用户,为了避免这个问题,当项目开发完之后,要将项目配置文件settings.py中的DEBUG设置为False。然后刷新,将不会再出现项目url的配置信息,而是返回一个标准的404页面。有时候我们想返回一个自定义的404页面,那么应该怎么做?自定义404页面
直接在Django项目模板目录templates(不是某个应用)下新建一个404.html,当用户输入一个不存在的地址或出现url配置错误或没有配置URl时,Django会自动返回这个页面。自定义500页面
500是视图函数中出现了错误。同样的,如果你不想用Django默认的500页面,那么同样在Django项目模板目录templates下新建一个500.html,出现视图函数错误时,Django会自动返回这个页面。
视图_捕获URL参数
进行url匹配时,把所需要的捕获的部分设置成一个正则表达式组,这样Django框架就会自动把匹配成功后相应组的内容作为参数传递给视图函数。有两种类型:捕获位置参数
参数名可以随意指定"""在应用下的urls.py中定义url配置项""" from django.conf.urls import url, include from django.contrib import admin from django.urls import path from . import views urlpatterns =[ url(r'^index', views.index), # 定义一个测试的url,当输入这个地址时,Django会将组匹配到的参数传递给后面的视图函数 url(r'test(\d+)', views.test), # 捕获url位置参数,只要你捕获了参数,那么在定义相应的视图函数时,必须要有形参 ] """在应用下的views.py中定义测试url对应的视图函数""" def test(request, para): # para为捕获到的参数 return HttpResponse(para)捕获关键字参数
在位置参数的基础上给正则表达式组命名即可。需要注意的是视图函数形参命名必须和该参数对应的组名一致。"""在应用下的urls.py中定义url配置项""" from django.conf.urls import url, include from django.contrib import admin from django.urls import path from . import views urlpatterns =[ url(r'^index', views.index), # 定义一个测试的url,当输入这个地址时,Django会将组匹配到的参数传递给后面的视图函数 url(r'^test(\d+)', views.test), # 捕获url位置参数,只要你捕获了参数,那么在定义相应的视图函数时,必须要有形参 # 需要注意的是视图函数形参命名必须和该参数对应的组名一致 url(r'^test(?P<num>\d+)', views.test), # 捕获url关键字参数,只要你捕获了参数,那么在定义相应的视图函数时,必须要有形参 ] """在应用下的views.py中定义测试url对应的视图函数""" def test(request, num): # para为捕获到的参数,参数名和正则表达式捕获到的组名一致 return HttpResponse(num)
视图函数的参数的作用
默认的request
接受HttpRequest对象,也是视图的第一个参数。该对象包含了浏览器请求的参数,比如请求头、请求参数之类的东西。通过post/get请求提交的参数就保存在该对象中。HttpRequest对象属性
在视图函数中可以直接用request.属性名调用- path:一个字符串,表示请求页面的完整路径,不含域名和参数部分。
- method:字符串,表示请求方式。
- encoding:字符串,表示提交的数据的编码方式。
- GET/POST:QueryDict类型对象,类似于字典,包含get/post请求的请求参数。
- FILES:一个类似于字典的对象,包含所有的上传文件。
- COOKIES:python标准字典,包含所有的cookie。
- session:一个即可以读又可以写的类似于字典的对象,表示当前的会话,只有当Django启用会话支持时才可以用。
视图_ajax(异步加载)
在不重新加载整个页面(即浏览器不再重新请求这个页面)的情况下,对页面内容进行局部刷新,目的是为了加快响应速度,提升用户体验。Ajax请求的过程
前端页面发起Ajax请求;后端视图函数处理Ajax请求,处理完返回JsonResponse()数据;浏览器收到返回的JSON格式数据之后,执行回调函数,改动页面内容。
例:用ajax给页面加一个提示
配置静态文件路径
在项目目录下新建一个static文件夹(和模板目录templates同级),然后在该目录下创建三个文件夹:js、css、images分别保存项目的js文件、css文件和图片文件;最后将jquery-1.12.4.min.js放在js文件夹中。最后在项目配置文件settings.py中新增STATICFILES_DIRS项,该项值为:[os.path.join(BASE_DIR, ‘static’)]。
"""在项目配置文件settings.py中""" STATIC_URL = '/static/' # 静态文件目录 STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]创建显示AJax页面的ajax.html模板文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Ajax请求测试</title> <!-- 导入JS文件--> <script src="/static/js/jquery-1.12.4.min.js"></script> <!-- 点击按钮执行的JS脚本--> <script> $(function () { //绑定btn的点击事件 $('#btn').click(function () { $.ajax({ /*ajax请求的url*/ 'url': '/ajax_handle', 'type': 'get', 'dataType': 'json' }).success(function (data) { //进行处理,data是Django后台(视图函数返回的数据) //alert(data.res) if (data.res == 1) { /*显示提示信息*/ $('#msg').show().html('提示信息!') } }) }) }) </script> <!-- ajax响应成功返回后在页面做的修改--> <style> #msg { /*默认不显示*/ display: none; color: red; } </style> </head> <body> <!--发送Ajax请求的按钮--> <input type="button" id="btn" value="Ajax请求"> <div id="msg"></div> </body> </html>定义视图函数
def ajax_test(request): """显示ajax页面""" return render(request, 'booktest/ajax.html') def ajax_handle(request): """处理ajax请求""" # 视图函数返回的数据{'res': 1} return JsonResponse({'res': 1})配置url
"""在应用的urls.py中的urlpatterns中添加下面这两项""" url(r'^ajax$', views.ajax_test), # 显示ajax页面 url(r'^ajax_handle$', views.ajax_handle)在地址栏中输入127.0.0.1:8000/ajax,进入,点击按钮

5、cookie和session
cookie和session用于用户状态保持,可以让用户在一段时间内无需重复登录就可以访问网站内容。
5.1 cookie
cookie是由服务器生成,存储在浏览器端的一小段文本信息。
cookie的特点
- 以键值对方式进行存储
- 通过浏览器访问一个网站时,会将浏览器存储的根网站相关的所有cookie信息发送给该网站的服务器。存在request.COOKIES中。
- cookie是基于域名安全的
- cookie可以设置过期时间,默认关闭浏览器就过期
通过HttpRequest对象的COOKIES属性进行会话的读写操作
- 设置cookie:
response.set_cookie('键', '值', max_age=秒数),设置cookie用的是HttpResponse对象 - 获取cookie:
request.COOKIES['键'] - 判断是否存在cookie:
键 in request.COOKIES
- 设置cookie:
5.2 session
session和cookie不同的一点是,session存储在服务器端。
session的特点
- session是以键值对进行存储的
- session依赖于cookie, 如果想还用Session,浏览器必须支持cookie.
- session默认过期时间是两周
通过HttpRequest对象的session属性进行会话的读写操作
- 以键值对形式写session:
request.session['键'] = 值 - 根据键读取值:
request.session.get('键', '默认值') - 清除所有session(删除值):
request.session.clear() - 清除session数据(删除键值):
request.session.flush() - 删除指定session:
del request.session['键'] - 设置session的过期时间:
request.session.set_expiry(秒数),默认两周过期
-检查是否有某个session:request.session.has_key('键')
- 以键值对形式写session:
cookie和session的应用场景
- cookie:记住用户名,安全性较低
- session:记住登录状态,保存密码等,安全性要求较高。
6、模板进阶(T)
6.1 回顾
模板功能
产生html,控制页面上展示的内容,模板文件不仅仅是一个html文件,模板文件包含两部分内容:- 静态内容:css、js、html
- 动态内容:用于动态去产生一些网页内容,通过模板语言来产生
模板文件的使用
通常是在视图函数中使用模板产生html内容返回给客户端。- 加载模板文件:loader.get_template, 获取模板文件内容。产生一个模板对象。
- 定义模板上下文,给模板文件传递数据:RequestContext
- 渲染模板产生html内容:render
- 上述步骤Django中已经封装成render方法了,可直接使用。
模板文件的加载顺序
- 首先去模板目录(templates)下面去找模板文件
- 如果在模板目录下找不到,就去应用下的模板目录下(前提是你的应用下要有templates目录,此处未在应用下创建templates目录)面去找, 找不到就会报错。
模板变量
模板变量名是由数字、字母、下划线组成的,不能以下划线开头。
使用模板变量:{{ 模板变量名 }}模板变量的解析顺序
例如:{{ book.book_title }}- 首先把book当成一个字典,把book_title当成键名进行取值,相当于book[‘book_title’]
- 上述取不到,就把book当成一个对象,把book_title当成一个属性
- 如果还是取不到,就把后面的book_title当成一个方法
- 如果还是取不到,就出错,结果用空字符串代替
- 就是说使用模板变量的时候,点前面可能是字典、对象、列表
6.2 模板标签
{% 代码段 %},代码段在大括号百分号中间。模板标签用于空值页面输出。
for循环
{% for x in 列表 %} // 列表不为空时执行 {% empty %} // 列表为空时执行 {% endfor %}可以通过 {{ forloop.counter }}得到for循环遍历到了第几次。
if 条件控制
{% if 条件 %} {% elif 条件 %} {% else %} {% endif %}关系比较运算符:>、<、>=、<=、==、!=
逻辑运算: not and or
##注意:比较操作符两边必须有空格
6.3 过滤器
过滤器用于对模板变量进行操作,改变模板变量的默认输出。
格式: {{ 模板变量 | 过滤器: 参数 }}
默认过滤器
自定义过滤器
自定义过滤器必须定义在应用下的templatetags包下,而且必须要有一个参数,最多只能有两个参数。在应用下新建一个包,叫templatetags
然后在templatetags下新建一个py文件
"""booktest/templatetags/filter.py中""" # 自定义过滤器 # 过滤器的本质其实就是Python函数 from django.template import Library # 实例化一个Library对象 register = Library() @register.filter def mod(num): """自定义过滤器判断num是否为偶数""" return num % 2 == 0在模板目录templates下对应应用下的模板文件中使用自定义过滤器
<!DOCTYPE html> <html lang="en"> <!--先加载过滤器--> {% load filter %} <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!--过滤器的使用方法都是一样的--> {% if val|mod %} <h2>val是偶数</h2> {% else %} <h2>val不是偶数</h2> </body> </html>
6.4 模板注释
单行注释:
{# 注释内容 #}多行注释:
{# comment #}注释内容{# endcomment #}
6.5 模板继承
模板继承是为了复用html页面中共有的代码,比如同一网站的导航条与版权信息。
继承
在子页面中:{% extends 'booktest/base.html' %},然后base.html有的内容子页面也就有了。需要注意的是,在父模板中要给子页面独有的内容预留位置,叫预留块。用:{% block 块名%}...{% endblock 块名 %}。子模板中重写块
在子模板中不重写块的内容,继承时就会使用父模板中的内容。
重写子模板中的内容:{% block 块名%}子模板内容{% endblock 块名 %}即用父模板内容又要重写父模板内容
{% block.super %}// 先继承父模板block内容,然后再重写{% block 块名%}子模板内容{% endblock 块名 %}模板继承什么时候用?
将所有页面共有的内容放在父模板中,什么位置的内容不同,就在什么地方预留块,然后在子页面中重写这个块。
6.6 html转义
在模板变量中如果包含<、>、&、'、"等,会被自动转义,原样显示(被当成字符串显示)。但是我就想让它能被当成正常的html语句怎么办?办法就是在模板文件中关闭html转义。
通过safe过滤器关闭
{{ 变量名|safe }}此时该变量会被当成html语句渲染到页面。
使用autoescape模板标签
{% autoescape %}模板变量{% endautoescape %}
6.7 CSRF攻击
Django是默认开启CSRF保护的,在项目配置文件settings.py中MIDDLEWARE项下:
'django.middleware.csrf.CsrfViewMiddleware', # Django默认开启CSRF,但是只针对post请求
无CSRF时,攻击者可以从其他站点发起相同的http请求,从而获取会话中的COOKIE/SESSION等用户信息,造成安全隐患。
- CSRF配置
页面中
<form action="/login/" method="POST"> {% csrf_token %} <input type="text" name="username" placeholder="用户名"/> <input type="password" name="password" placeholder="密码"/> <input type="submit" value="登录"/> </form>Ajax配置
注意要引用脚本jquery.cookie.js<script src="/static/js/jquery-1.12.4.js"></script> <script src="/static/js/jquery.cookie.js"></script> <script> // ajax csrf配置 var csrftoken = $.cookie('csrftoken'); function csrfSafeMethod(method) { return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $.ajaxSetup({ beforeSend: function(xhr, settings) { if (!csrfSafeMethod(settings.type) && !this.crossDomain) { xhr.setRequestHeader("X-CSRFToken", csrftoken); } } }); </script>
- 视图函数配置
Django中已经写好了CSRF的装饰器,便于我们给某个具体的视图函数配置CSRF。给视图函数添加CSRF
from django.views.decorators.csrf import csrf_exempt, csrf_protect @csrf_protect def login(request): """显示登录界面""" # 有用户session if request.session.has_key('isLogin'): return redirect('/index') # 无用户session,返回登录页 else: # 获取cookie和username if 'account' in request.COOKIES: # 获取账号 account = request.COOKIES['account'] else: account = '' return render(request, 'booktest/login.html', {'account': account})如果要关闭某个视图函数的CSRF,使用
csrf_exempt装饰器即可。
6.8 URL反向解析
作用:当某一个url配置的地址发生变化时,页面上使用反向解析生成的地址不需要发生变化。
暂时没有用到,放一篇参考文献。
7、Django其他技术
7.1 静态文件
在网页中使用的JS、CSS、图片、JSON文件等都属于静态文件。
在项目目录下新建static目录,然后在此目录下分别给每一类静态文件创建一个文件夹:

在项目配置文件settings.py中配置静态文件的路径
STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
使用的时候直接: /static/css/xx.css就可以了。
7.2 中间件
中间件函数是Django框架留给我们预留的函数接口,让我们干预请求和应答过程。
- 获取浏览器端的IP地址
request.META[‘REMOTE_ADDR’], 通过视图函数的request参数可以获取到客户机的IP地址
还有一部分内容,后期用的时候再补充吧