F对象
一个F对象代表数据库中某个字段的信息
F对象通常是对数据库中的字段值在不加载到内存中的情况下直接在数据库服务器端进行操作
F对象在 数据包 django.db.models 中.使用时需要通过如下语句进行加载
from django.db.models import F
作用:
- 在执行过程中获取某列的值并对其直接进行操作
- 当同时对数据库中两个字段的值进行比较获取 QuerySet 数据集时,可以便用F对象
说明:
- 一个 F()对象代表了一个model的字段的值
使用它就可以直接参考model的field和执行数据库操作而不用再把它们(model field)查询出来放到python内存中。
语法:
1from django.db.models import F2F('列名')示例1
- 更新Book实例中所有的制场价涨10元
xxxxxxxxxx61models.Book.objects.all().update(market_price=F('market_price')+10)2# 以下做法好于如下代码3books = models.Book.objects.all()4for book in books:5book.update(market_price=book.marget_price+10)6book.save()示例2
- 对数据库中两个字段的值进行比较,列出哪儿些书的零售价高于定价?
xxxxxxxxxx51from django.db.models import F2from bookstore import models3books = models.Book.objects.filter(market_price__gt=F('price'))4for book in books:5print(book.title, '定价:', book.price, '现价:', book.market_price)
Q对象 – Q()
当在获取查询结果集 使用复杂的逻辑或
|、 逻辑非~等操作时可以借助于 Q对象进行操作如: 想找出定价低于20元 或 清华大学出版社的全部书,可以写成
xxxxxxxxxx11models.Book.objects.filter(Q(price__lt=20)|Q(pub="清华大学出版社"))Q对象在 数据包 django.db.models 中。需要先导入再使用
from django.db.models import F
作用
- 在条件中用来实现除 and(&) 以外的 or(|) 或 not(~) 操作
运算符:
- & 与操作
- | 或操作
- 〜 非操作
语法
xxxxxxxxxx51from django.db.models import Q2Q(条件1)|Q(条件2) # 条件1成立或条件2成立3Q(条件1)&Q(条件2) # 条件1和条件2同时成立4Q(条件1)&~Q(条件2) # 条件1成立且条件2不成立5...示例
xxxxxxxxxx51from django.db.models import Q2# 查找清华大学出版社的书或价格低于50的书3models.Book.objects.filter(Q(market_price__lt=50) | Q(pub_house='清华大学出版社'))4# 查找不是机械工业出版社的书且价格低于50的书5models.Book.objects.filter(Q(market_price__lt=50) & ~Q(pub_house='机械工业出版社'))
原生的数据库操作方法
使用Entry.objects.raw()进行 数据库查询操作查询
- 在django中,可以使用模型管理器的raw方法来执行select语句进行数据查询
语法:
Entry.objects.raw(sql语句)
用法
Entry.objects.raw('sql语句')
返回值:
- QuerySet 集合对象
示例
x1books = models.Book.objects.raw('select * from bookstore_book')23for book in books:4print(book)
使用django中的游标cursor对数据库进行 增删改操作
在Django中可以使用 如UPDATE,DELETE等SQL语句对数据库进行操作。
在DJaogo中使用上述非查询语句必须使用游标进行操作
使用步骤:
导入cursor所在的包
Django中的游标cursor定义在 django.db.connection包中,使用前需要先导入
如:
from django.db import connection
用创建cursor类的构造函数创建cursor对象,再使用cursor对象,为保证在出现异常时能释放cursor资源,通常使用with语句进行创建操作
如:
xxxxxxxxxx31from django.db import connection2with connection.cursor() as cur:3cur.execute('执行SQL语句')
示例
xxxxxxxxxx81# 用SQL语句将id 为 10的 书的出版社改为 "XXX出版社"2from django.db import connection3with connection.cursor() as cur:4cur.execute('update bookstore_book set pub_house="XXX出版社" where id=10;')56with connection.cursor() as cur:7# 删除 id为1的一条记录8cur.execute('delete from bookstore_book where id=10;')
admin 后台数据库管理
django 提供了比较完善的后台管理数据库的接口,可供开发过程中调用和测试使用
django 会搜集所有已注册的模型类,为这些模型类提拱数据管理界面,供开发者使用
使用步骤:
创建后台管理帐号:
后台管理–创建管理员帐号
$ python3 manage.py createsuperuser根据提示完成注册,参考如下:
xxxxxxxxxx71$ python3 manage.py createsuperuser2Username (leave blank to use 'tarena'): tarena # 此处输入用户名3Email address: weimz@tedu.cn # 此处输入邮箱4Password: # 此处输入密码(密码要复杂些,否则会提示密码太简单)5Password (again): # 再次输入重复密码6Superuser created successfully.7$
用注册的帐号登陆后台管理界面
后台管理的登录地址:
自定义后台管理数据表
若要自己定义的模型类也能在
/admin后台管理界中显示和管理,需要将自己的类注册到后台管理界面添加自己定义模型类的后台管理数据表的,需要用
admin.site.register(自定义模型类)方法进行注册配置步骤如下:
在应用app中的admin.py中导入注册要管理的模型models类, 如:
xxxxxxxxxx11from . import models调用 admin.site.register 方法进行注册,如:
xxxxxxxxxx21from django.contrib import admin2admin.site.register(自定义模型类)
如: 在 bookstore/admin.py 添加如下代码对Book类进行管理
示例:
xxxxxxxxxx71# file: bookstore/admin.py2from django.contrib import admin3# Register your models here.45from . import models6...7admin.site.register(models.Book) # 将Book类注册为可管理页面
修改后台Models的展现形式
在admin后台管理数据库中对自定义的数据记录都展示为
XXXX object类型的记录,不便于阅读和判断在用户自定义的模型类中可以重写
def __str__(self):方法解决显示问题,如:- 在 自定义模型类中重写 str(self) 方法返回显示文字内容:
xxxxxxxxxx41classd Bookstore(models.Model):2...3def __str__(self):4return "书名" + self.title
模型管理器类
作用:
- 用后台管理界面添加便于操作的新功能。
说明:
- 后台管理器类须继承自
django.contrib.admin里的ModelAdmin类
- 后台管理器类须继承自
模型管理器的使用方法:
在
<应用app>/admin.py里定义模型管理器类xxxxxxxxxx21class XXXX_Manager(admin.ModelAdmin):2......注册管理器与模型类关联
xxxxxxxxxx31from django.contrib import admin2from . import models3admin.site.register(models.YYYY, XXXX_Manager) # 注册models.YYYY 模型类与 管理器类 XXXX_Manager 关联
示例:
xxxxxxxxxx81# file : bookstore/admin.py2from django.contrib import admin3from . import models45class BookAdmin(admin.ModelAdmin):6list_display = ['id', 'title', 'price', 'market_price']78admin.site.register(models.Book, BookAdmin)- 进入http://127.0.0.1:8000/admin/bookstore/book/ 查看显示方式和以前有所不同
模型管理器类ModelAdmin中实现的高级管理功能
- list_display 去控制哪些字段会显示在Admin 的修改列表页面中。
- list_display_links 可以控制list_display中的字段是否应该链接到对象的“更改”页面。
- list_filter 设置激活激活Admin 修改列表页面右侧栏中的过滤器
- search_fields 设置启用Admin 更改列表页面上的搜索框。
- list_editable 设置为模型上的字段名称列表,这将允许在更改列表页面上进行编辑。
- 其它参见https://docs.djangoproject.com/en/1.11/ref/contrib/admin/
数据库表管理
修改模型类字段的显示名字
模型类各字段的第一个参数为 verbose_name,此字段显示的名字会在后台数据库管理页面显示
通过 verbose_name 字段选项,修改显示名称示例如下:
xxxxxxxxxx41title = models.CharField(2max_length = 30,3verbose_name='显示名称'4)
通过Meta内嵌类 定义模型类的属性及展现形式
模型类可以通过定义内部类class Meta 来重新定义当前模型类和数据表的一些属性信息
用法格式如下:
xxxxxxxxxx91class Book(models.Model):2title = CharField(....)3class Meta:41. db_table = '数据表名'5- 该模型所用的数据表的名称。(设置完成后需要立马更新同步数据库)62. verbose_name = '单数名'7- 给模型对象的一个易于理解的名称(单数),用于显示在/admin管理界面中83. verbose_name_plural = '复数名'9- 该对象复数形式的名称(复数),用于显示在/admin管理界面中示例:
xxxxxxxxxx41class Meta:2db_table = 'book_table' # 将原数据表名"bookstore_book" 换为 "book_table",请查看数据表3verbose_name = 'booooook'4verbose_name_plural = 'booksssssss' # 去127.0.0.1:8000/admin下看看哪儿变化了?
练习:
- 将Book模型类 和 Author 模型类都加入后台管理
- 制作一个AuthorManager管理器类,让后台管理Authors列表中显示作者的ID、姓名、年龄信息
- 用后台管理程序 添加三条 Author 记录
- 修改其中一条记录的年龄
- 删除最后一条添加的记录
- 将bookstore_author 数名表名称改为myauthor (需要重新迁移数据库)
<!–
xxxxxxxxxx191练习:21.修改 Publisher 的后台显示31.更改表名为 publisher42.修改后台展示名称为 - 出版社53.修改每个属性对应的中文名62.修改 Book 后台显示71.更改表名为 book82.修改后台展示名称 - 书籍93.修改每个属性对应的中文名10112.练习12为 Publisher 增加高级管理功能131. 在列表页中显示 name,address,city 属性142. 在列表页中 address 和 city 是可编辑的153. 右侧增加过滤器 , 允许按照city筛选164. 顶部增加搜索框,允许按照name和website搜索175. 详情页中分组显示:181.name,address,city 基本信息192.country,website 高级信息,可折叠
–>
数据表关联关系映射 Relationship Map
在关系型数据库中,通常不会把所有数据都放在同一张表中,这样做会额外占用内存空间,
在关系列数据库中通常用表关联来解决数据库。
常用的表关联方式有三种:
一对一映射
- 如: 一个身份证对应一个人
一对多映射
- 如: 一个班级可以有多个学生
多对多映射
- 如: 一个学生可以报多个课程,一个课程可以有多个学生学习
一对一映射
- 一对一是表示现实事物间存在的一对一的对应关系。
- 如:一个家庭只有一个户主,一个男人有一个妻子,一个人有一个唯一的指纹信息等
语法
xxxxxxxxxx61在关联的两个类中的任何一个类中:2class A(model.Model):3...45class B(model.Model):6属性 = models.OneToOneField(A)用法示例
创建作家和作家妻子类
xxxxxxxxxx111# file : xxxxxxxx/models.py2from django.db import models34class Author(models.Model):5'''作家模型类'''6name = models.CharField('作家', max_length=50)78class Wife(models.Model):9'''作家妻子模型类'''10name = models.CharField("妻子", max_length=50)11author = models.OneToOneField(Author) # 增加一对一属性查询
- 在 Wife 对象中,通过 author 属性找到对应的author对象
- 在 Author 对象中,通过 wife 属性找到对应的wife对象
创始一对一的数据记录
xxxxxxxxxx41from . import models2author1 = models.Author.objects.create(name='王老师')3wife1 = models.Wife.objects.create(name='王夫人', author=author1) # 关联王老师4author2 = models.Author.objects.create(name='小泽老师') # 一对一可以没有数据对应的数据一对一数据的相互获取
正向查询
- 直接通过关联属性查询即可
xxxxxxxxxx41# 通过 wife 找 author2from . import models3wife = models.Wife.objects.get(name='王夫人')4print(wife.name, '的老公是', wife.author.name)反向查询
- 通过反向引用属性查询
- 反向引用属性为
实例对象.引用类名(小写),如作家的反向引用为作家对象.wife - 当反向引用不存在时,则会触发异常
xxxxxxxxxx81# 通过 author.wife 引用属性 找 wife,如果没有对应的wife刚触发异常2author1 = models.Author.objects.get(name='王老师')3print(author1.name, '的妻子是', author1.wife.name)4author2 = models.Author.objects.get(name='小泽老师')5try:6print(author2.name, '的妻子是', author2.wife.name)7except:8print(author2.name, '还没有妻子')
作用:
- 主要是解决常用数据不常用数据的存储问题,把经常加载的一个数据放在主表中,不常用数据放在另一个副表中,这样在访问主表数据时不需要加载副表中的数据以提高访问速度提高效率和节省内存空间,如经常把书的内容和书名建成两张表,因为在网站上经常访问书名等信息,但不需要得到书的内容。
练习:
创建一个Wife模型类,属性如下
- name
- age
在Wife类中增加一对一关联关系,引用 Author
同步回数据库并观察结果
一对多映射
- 一对多是表示现实事物间存在的一对多的对应关系。
- 如:一个学校有多个班级,一个班级有多个学生, 一本图书只能属于一个出版社,一个出版社允许出版多本图书
用法语法
- 当一个A类对象可以关联多个B类对象时
xxxxxxxxxx51class A(model.Model):2...34class B(model.Model):5属性 = models.ForeignKey(多对一中"一"的模型类, ...)外键类ForeignKey
构造函数:
xxxxxxxxxx11ForeignKey(to, on_delete, **options)常用参数:
on_delete
- models.CASCADE 级联删除。 Django模拟SQL约束ON DELETE CASCADE的行为,并删除包含ForeignKey的对象。
- models.PROTECT 抛出ProtectedError 以阻止被引用对象的删除;
- SET_NULL 设置ForeignKey null;只有null是True才有可能。
- SET_DEFAULT 将ForeignKey设置为其默认值;必须设置ForeignKey的默认值。
- … 其它参请参考文档 https://yiyibooks.cn/xx/Django_1.11.6/ref/index.html ForeignKey部分
**options可以是常用的字段选项如:- null
- unique等
- …
示例
有二个出版社对应五本书的情况.
清华大学出版社有书- C++
- Java
- Python
北京大学出版社有书- 西游记
- 水浒
定义一对多类
xxxxxxxxxx101# file: myorm/models.py2from django.db import models3class Publisher(models.Model):4'''出版社'''5name = models.CharField('名称', max_length=50, unique=True)67class Book(models.Model):8title = models.CharField('书名', max_length=50)9publisher = models.ForeignKey(Publisher, null=True)10
创建一对多的对象
xxxxxxxxxx101# file: xxxxx/views.py2from . import models3pub1 = models.Publisher.objects.create(name='清华大学出版社')4models.Book.objects.create(title='C++', publisher=pub1)5models.Book.objects.create(title='Java', publisher=pub1)6models.Book.objects.create(title='Python', publisher=pub1)78pub2 = models.Publisher.objects.create(name='北京大学出版社')9models.Book.objects.create(title='西游记', publisher=pub2)10models.Book.objects.create(title='水浒', publisher=pub2)查询:
- 通过多查一
xxxxxxxxxx31# 通过一本书找到对应的出版社2abook = models.Book.objects.get(id=1)3print(abook.title, '的出版社是:', abook.publisher.name)- 通过一查多
xxxxxxxxxx71# 通过出版社查询对应的书2pub1 = models.Publisher.objects.get(name='清华大学出版社')3books = pub1.book_set.all() # 通过book_set 获取pub1对应的多个Book数据对象4# books = models.Book.objects.filter(publisher=pub1) # 也可以采用此方式获取5print("清华大学出版社的书有:")6for book in books:7print(book.title)
练习:
- 完成Book 和 Publisher 之间的一对多
- 查看数据库效果
- 登录到后台,查看Book实体
数据查询
通过 Book 查询 Publisher
xxxxxxxxxx31通过 publisher 属性查询即可2练习:3查询 西游记 对应的出版社信息,打印在终端上通过 Publisher 查询 对应的所有的 Books
xxxxxxxxxx21Django会在Publisher中增加一个属性来表示对对应的Book们的查询引用2属性:book_set(Entry.objects)
多对多映射
- 多对多表达对象之间多对多复杂关系,如: 每个人都有不同的学校(小学,初中,高中,…),每个学校都有不同的学生…
语法
xxxxxxxxxx21在关联的两个类中的任意一个类中,增加:2属性 = models.ManyToManyField(Entry)示例
xxxxxxxxxx101一个作者可以出版多本图书2一本图书可以被多名作者同时编写34class Author(models.Model):5xxxx xxxx67class Book(models.Model):8xxxx xxxx910authors = models.ManyToManyField(Author)数据查询
通过 Book 查询对应的所有的 Authors
xxxxxxxxxx51可以通过authors表示对应所有Author的查询对象23book.authors.all() -> 获取 book 对应的所有的author的信息45book.authors.filter(age__gt=80) -> 获取book对应的作者中年龄大于80岁的作者的信息通过 Author 查询对应的所有的Books
xxxxxxxxxx71Django会生成一个属性 book_set 用于表示对对应的book的查询对象相关操作•2author.book_set.all()3author.book_set.filter()4author.book_set.create(...) # 创建新书并联作用author5author.book_set.add(book) # 添加已有的书为当前作者author6author.book_set.clear() # 删除author所有并联的书7author.book_set.remove() # 删除所author所有并联的书
示例:
- 多对多模型
xxxxxxxxxx101class Author(models.Model):2'''作家模型类'''3name = models.CharField('作家', max_length=50)4def __str__(self):5return self.name6class Book(models.Model):7title = models.CharField('书名', max_length=50)8author = models.ManyToManyField(Author, null=True)9def __str__(self):10return self.title- 多对多视图操作
xxxxxxxxxx311from django.http import HttpResponse23from . import models45def many2many_init(request):6# 创建两人个作者7author1 = models.Author.objects.create(name='吕泽')8author2 = models.Author.objects.create(name='魏老师')910# 吕择和魏老师同时写了一本Python11book11 = author1.book_set.create(title="Python")12author2.book_set.add(book11) #1314# 魏老师还写了两本书15book21 = author2.book_set.create(title="C") # 创建一本新书"C"16book22 = author2.book_set.create(title="C++") # 创建一本新书"C++"1718return HttpResponse("初始化成功")1920def show_many2many(request):21authors = models.Author.objects.all()22for auth in authors:23print("作者:", auth.name, '发出版了', auth.book_set.count(), '本书: ')24for book in books:25print(' ', book.title)26print("----显示书和作者的关系----")27books = models.Book.objects.all()28for book in books:29auths = book.author.all()30print(book.title, '的作者是:', '、'.join([str(x.name) for x in auths]))31return HttpResponse("显示成功,请查看服务器端控制台终端")- 多对多最终的SQL结果
xxxxxxxxxx291mysql> select * from myorm2_author;2+----+-----------+3| id | name |4+----+-----------+5| 11 | 吕泽 |6| 12 | 魏老师 |7+----+-----------+82 rows in set (0.00 sec)910mysql> select * from myorm2_book;11+----+--------+12| id | title |13+----+--------+14| 13 | Python |15| 14 | C |16| 15 | C++ |17+----+--------+183 rows in set (0.00 sec)1920mysql> select * from myorm2_book_author;21+----+---------+-----------+22| id | book_id | author_id |23+----+---------+-----------+24| 17 | 13 | 11 |25| 20 | 13 | 12 |26| 18 | 14 | 12 |27| 19 | 15 | 12 |28+----+---------+-----------+294 rows in set (0.00 sec)- 示例示意图
2.Django中的cookies 使用 响应对象 将cookie保存进客户端 1.响应对象 1. HttpResponse() resp = HttpResponse() 2. render() resp = render(request,'xxx.html',locals()) 3. redirect() resp = redirect('/') 2.保存cookie 响应对象.set_cookie(key,value,expires) key:cookie的名字 value:cookie的值 expires:保存时长,以s为单位的数字(s不写) 3.获取cookie request.COOKIES 封装了当前站点下所有的cookie – 字典
cookies 和 session(会话)
cookies
cookies是保存在客户端浏览器上的存储空间,通常用来记录浏览器端自己的信息和当前连接的确认信息
cookies 在浏览器上是以键-值对的形式进行存储的,键和值都是以ASCII字符串的形存储(不能是中文字符串)
在Django 服务器端来设置 设置浏览器的COOKIE 必须通过 HttpResponse 对象来完成
HttpResponse 关于COOKIE的方法
添加、修改COOKIE
HttpResponse.set_cookie(key, value='', max_age=None, expires=None)
- key:cookie的名字
- value:cookie的值
- expires:保存时长,以s为单位的数字(s不写)
删除COOKIE
- HttpResponse.delete_cookie(key)
- 删除指定的key 的Cookie。 如果key 不存在则什么也不发生。
Django中的cookies
使用 响应对象HttpResponse 等 将cookie保存进客户端
方法1
xxxxxxxxxx31from django.http import HttpResponse2resp = HttpResponse()3resp.set_cookie('cookies名', cookies值, 超期时间)方法二, 使用render对象
xxxxxxxxxx31from django.shortcuts import render2resp = render(request,'xxx.html',locals())3resp.set_cookie('cookies名', cookies值, 超期时间)方法三, 使用redirect对象
xxxxxxxxxx31from django.shortcuts import redirect2resp = redirect('/')3resp.set_cookie('cookies名', cookies值, 超期时间)
获取cookie
通过 request.COOKIES 获取客户端的 COOKIES数据
xxxxxxxxxx21resp = redirect('/')2resp.set_cookie('cookies名', cookies值, 超期时间)
注:
- Chrome 浏览器 可能通过开发者工具的
Application>>Storage>>Cookies查看和操作浏览器端所有的 Cookies 值
- Chrome 浏览器 可能通过开发者工具的
cookies 示例
xxxxxxxxxx341# file : <项目名>/urls.py2from . import views34urlpatterns = [5 url(r'^admin/', admin.site.urls),6 # 增删改cookie7 url(r'^add_cookie', views.add_cookie),8 url(r'^mod_cookie/(\d+)', views.mod_cookie),9 url(r'^del_cookie', views.del_cookie),10 url(r'^show_cookie', views.show_cookie),11]12 13# file : <项目名>/views.py14from . import views15from django.http import HttpResponse16def add_cookie(request):17 responds = HttpResponse("已添加mycookie_var1,值为123")18 responds.set_cookie('mycookie_var1', 123, 3600)19 return responds2021def mod_cookie(request, new_value):22 responds = HttpResponse("已修改mycookie_var1,新值为"+new_value)23 responds.set_cookie('mycookie_var1', new_value, 3600)24 return responds2526def del_cookie(request):27 responds = HttpResponse("已删除mycookie_var1")28 responds.delete_cookie('mycookie_var1')29 return responds3031def show_cookie(request):32 value = request.COOKIES.get('mycookie_var1', '没有值!')33 print("cookie mycookie_var1 = ", value)34 return HttpResponse("mycookie_var1:" + value)session
session是在服务器上开辟一段空间用于保留浏览器和服务器交互时的重要数据
每个客户端都可以在服务器端有一个独立的Session
http协议是无状态的:每次请求都是一次新的请求,不会记得之前通信的状态
客户端与服务器端的一次通信,就是一次会话
实现状态保持的方式:在客户端或服务器端存储与会话有关的数据
存储方式包括cookie、session,会话一般指session对象
使用cookie,所有数据存储在客户端,注意不要存储敏感信息
推荐使用sesison方式,所有数据存储在服务器端,在客户端cookie中存储session_id
状态保持的目的是在一段时间内跟踪请求者的状态,可以实现跨页面访问当前请求者的数据
注意:不同的请求者之间不会共享这个数据,与请求者一一对应
什么是session
- session – 会话
- 在服务器上开辟一段空间用于保留浏览器和服务器交互时的重要数据
Django启用Session
在 settings.py 文件中
项INSTALLED_APPS列表中添加:
- 'django.contrib.sessions',
项MIDDLEWARE_CLASSES列表中添加:
- 'django.contrib.sessions.middleware.SessionMiddleware',
session的基本操作:
Session对于象是一个 QueryDict 字典, 可以用类拟于字典的方式进行操作
保存 session 的值到服务器
request.session[键] = 值- 如:
request.session['KEY'] = VALUE
获取session的值
VALUE = request.session['KEY']- 或
VALUE = request.session.get('KEY', 缺省值)
删除session的值
del request.session['KEY']
在 settings.py 中有关 session 的设置
- SESSION_COOKIE_AGE 作用:指定sessionid在cookies中的保存时长 SESSION_COOKIE_AGE = 60*30
- SESSION_EXPIRE_AT_BROWSER_CLOSE = True 设置只要浏览器关闭时,session就失效
注: 当使用session时需要迁移数据库,否则会出现错误
xxxxxxxxxx21$ python3 manage.py makemigrations2$ python3 manage.py migrate- session 示例
xxxxxxxxxx341# file : <项目名>/urls.py2from . import views34urlpatterns = [5 url(r'^admin/', admin.site.urls),6 # 增删改session7 url(r'^add_session', views.add_session),8 url(r'^mod_session/(\d+)', views.mod_session),9 url(r'^del_session', views.del_session),10 url(r'^show_session', views.show_session),11]12 13# file : <项目名>/views.py14from . import views15from django.http import HttpResponse16def add_session(request):17 request.session['mysession_var'] = 10018 responds = HttpResponse("添加session")19 return responds20def mod_session(request, new_value):21 request.session['mysession_var'] = new_value22 responds = HttpResponse("修改session成功")23 return responds24def del_session(request):25 try:26 del request.session['mysession_var']27 responds = HttpResponse("删除session成功")28 except:29 responds = HttpResponse("删除session失败")30 return responds31def show_session(request):32 mysession_var = request.session.get('mysession_var', '没有值!')33 print("mysession_var = ", mysession_var)34 return HttpResponse("mysession_var = " + str(mysession_var))中间件 Middleware
中间件是 Django 请求/响应处理的钩子框架。它是一个轻量级的、低级的“插件”系统,用于全局改变 Django 的输入或输出。
每个中间件组件负责做一些特定的功能。例如,Django 包含一个中间件组件 AuthenticationMiddleware,它使用会话将用户与请求关联起来。
他的文档解释了中间件是如何工作的,如何激活中间件,以及如何编写自己的中间件。Django 具有一些内置的中间件,你可以直接使用。它们被记录在 built-in middleware reference 中。
中间件类:
中间件类须继承自
django.utils.deprecation.MiddlewareMixin类中间件类须实现下列五个方法中的一个或多个:
def process_request(self, request):执行视图之前被调用,在每个请求上调用,返回None或HttpResponse对象def process_view(self, request, callback, callback_args, callback_kwargs):调用视图之前被调用,在每个请求上调用,返回None或HttpResponse对象def process_response(self, request, response):所有响应返回浏览器之前被调用,在每个请求上调用,返回HttpResponse对象def process_exception(self, request, exception):当处理过程中抛出异常时调用,返回一个HttpResponse对象def process_template_response(self, request, response):在视图刚好执行完毕之后被调用,在每个请求上调用,返回实现了render方法的响应对象
注: 中间件中的大多数方法在返回None时表示忽略当前操作进入下一项事件,当返回HttpResponese对象时表示此请求结果,直接返回给客户端
编写中间件类:
xxxxxxxxxx211# file : middleware/mymiddleware.py2from django.http import HttpResponse, Http4043from django.utils.deprecation import MiddlewareMixin45class MyMiddleWare(MiddlewareMixin):6 def process_request(self, request):7 print("中间件方法 process_request 被调用")89 def process_view(self, request, callback, callback_args, callback_kwargs):10 print("中间件方法 process_view 被调用")1112 def process_response(self, request, response):13 print("中间件方法 process_response 被调用")14 return response1516 def process_exception(self, request, exception):17 print("中间件方法 process_exception 被调用")1819 def process_template_response(self, request, response):20 print("中间件方法 process_template_response 被调用")21 return response- 注册中间件:
xxxxxxxxxx51# file : settings.py2MIDDLEWARE = [3 ...4 'middleware.mymiddleware.MyMiddleWare',5]中间件的执行过程
- <!–
参考文档:
练习
用中间件实现强制某个IP地址只能向/test 发送一次GET请求
提示:
- request.META['REMOTE_ADDR'] 可以得到远程客户端的IP地址
- request.path_info 可以得到客户端访问的GET请求路由信息
答案:
xxxxxxxxxx171from django.http import HttpResponse, Http4042from django.utils.deprecation import MiddlewareMixin3import re4class VisitLimit(MiddlewareMixin):5'''此中间件限制一个IP地址对应的访问/user/login 的次数不能改过10次,超过后禁止使用'''6visit_times = {} # 此字典用于记录客户端IP地址有访问次数7def process_request(self, request):8ip_address = request.META['REMOTE_ADDR'] # 得到IP地址9if not re.match('^/test', request.path_info):10return11times = self.visit_times.get(ip_address, 0)12print("IP:", ip_address, '已经访问过', times, '次!:', request.path_info)13self.visit_times[ip_address] = times + 114if times < 5:15return1617return HttpResponse('你已经访问过' + str(times) + '次,您被禁止了')
跨站请求伪造保护 CSRF
跨站请求伪造攻击
- 某些恶意网站上包含链接、表单按钮或者JavaScript,它们会利用登录过的用户在浏览器中的认证信息试图在你的网站上完成某些操作,这就是跨站请求伪造。
CSRF
xxxxxxxxxx21Cross-Site Request Forgey2跨 站点 请求 伪装说明:
- CSRF中间件和模板标签提供对跨站请求伪造简单易用的防护。
作用:
- 不让其它表单提交到此 Django 服务器
解决方案:
取消 csrf 验证(不推荐)
- 删除 settings.py 中 MIDDLEWARE 中的
django.middleware.csrf.CsrfViewMiddleware的中间件
- 删除 settings.py 中 MIDDLEWARE 中的
开放验证
xxxxxxxxxx41在视图处理函数增加: @csrf_protect2@csrf_protect3def post_views(request):4pass通过验证
xxxxxxxxxx21需要在表单中增加一个标签2{% csrf_token %}
练习: 项目的注册部分
创建一个数据库 – FruitDay
创建实体类 – Users
- uphone – varchar(11)
- upwd – varchar(50)
- uemail – varchar(245)
- uname – varchar(20)
- isActive – tinyint 默认值为1 (True)
完善注册 – /register/
- 如果是get请求,则去往register.html
- 如果是post请求,则处理请求数据 将提交的数据保存回数据库


