day17 2018-08-12 Django框架02 1. 今日内容: 1. 新建Django项目梳理 1. 模板文件路径配置 2. 数据库配置 3. 静态文件配置 4. 注释掉csrf中间件那一行 2. Django默认sqlite3数据库的简单用法 3. 路由系统进阶:https://www.cnblogs.com/liwenzhou/articles/8271147.html - 动态路由 urls.py中通过正则表达式的分组匹配,捕获用户访问的url中的值,传递给视图函数 分组匹配: 相当于给视图函数传递 位置参数 分组命名匹配: 相当于给视图函数传递 关键字参数 - name 防止将url硬编码到我们的业务逻辑代码中,给url起别名 通过别名,反向找到 url 在views.py中: from django.urls import reverse 具体的url = reverse('url别名') 4. 视图函数进阶:https://www.cnblogs.com/liwenzhou/articles/8305104.html 1. views.py 1. 基础必会三件套 1. HttpResponse('字符串') 2. render(request, "xx.html", {"key": value}) 3. redirect("/其它的url/") 2. FBV(Function Base View) 基于函数的视图 通过request.method == "POST" 去判断 3. CBV(Class Base View) 基于类的视图 1. 必须继承views.View --> from django import views 2. 写一个自己的视图类 3. 通过定义不同的方法,来处理用户不同的请求 4. 在urls.py中注册视图的时候要写 views.类名.as_view() 2. request对象的常用属性和方法 request表示的是和用户请求相关的所有数据 1. request.method --> 用户当前请求的请求方法 2. request.GET --> 用户请求中url中的参数 3. request.POST --> 用户POST请求的数据 4. request.path_info --> 用户访问的url路径是什么 3. Django上传文件 1. 前端页面 1. form表单一定要有action,method必须是post 2. 一定要配置enctype="multipart/form-data 2. 后端: def post(self, request): # 拿到用户发送的文件数据 file_obj = request.FILES.get("code") # 保存下来 # 1. 拿到用户上传的文件名 filename = file_obj.name # 2. 在服务端创建一个同名的文件 with open(filename, "wb") as f: # 3. 从用户上传的文件对象中一点一点读数据,往我本地创建的文件句柄里一点一点写 for i in file_obj.chunks(): f.write(i) return HttpResponse("上传成功!") 4. JsonResponse 专门用来返回JSON格式数据的响应对象 from django.http import JsonResponse 5. 模板引擎进阶:https://www.cnblogs.com/liwenzhou/p/7931828.html 1. 已经学过的Django模板语言的语法 1. 两个语法: 1. {{ }} --> 跟变量相关的操作 2. {% %} --> 跟逻辑相关的操作 2. 变量相关 1. 传字典或对象类型的数据 obj.name/obj.age 2. 传数组类型的数据 obj.索引值 3. 日期格式化{{ today|date:"Y-m-d H:i:s"}}
4. 显示真正的html代码{{ link|safe }}
2. 母板 1. 为什么要用母版? 不同的页面有大量重复的代码,我们可以把公用的部分提取出来放在单独一个文件 2. 怎么使用? 1. 在子页面 通过使用 {% extends ‘模板名’ %} --> 放在子页面的最上面 2. {% block xx %}{% endblock %} 3. 组件 把单独的一段html代码放在一个文件 使用 {% include '组件名' %}导入 6. CSRF 1. 为什么要有csrf_token? 2. Django中如何使用? 在render的页面上写上{% csrf_token %} 3. 如果是form表单形式提交,必须放在form表单中 7. ORM单表查询13条+外键操作(一对多): 1. ORM上周知识点: 1. 查询 1. 查所有 models.Publisher.objects.all() 2. 查某个具体的记录 models.Publisher.objects.get(id=1) --> 注意查询条件不成立就报错 2. 删除一条记录 models.Publisher.objects.get(id=1).delete() 3. 创建一条记录 models.Publisher.objects.create(name="新出版社名字", addr="出版社地址") 4. 修改一条记录 obj = models.Publisher.objects.get(id=1) obj.name = "新名字" obj.save() 2. 字段和参数: https://www.cnblogs.com/liwenzhou/p/8688919.html 1. 上周字段和参数: 1. models.AutoField(primary_key=True) 2. models.CharField(max_length=32) 2. 常用字段和参数 1. 字段 1. CharField 2. AutoField 3. DateField 4. DateTimeField() 5. IntergeField() 2. 参数 1. null=True 2. default=默认值 3. unique=True 4. 时间字段 1. auto_now_add=True 第一次创建时 2. auto_add=True 每次更新时 3. ORM必知必会单表查询13条 1. all() --> 查询所有结果 2. filter() --> 根据查询条件查询数据库的 3. get() --> 获取一个唯一的值 4. exclude() --> 将符合条件的都剔除掉,留下不符合条件的 5. values('字段名', ...) --> 返回一个QuerySet,里面是字典 6. values_list(字段名', ...) --> 返回一个QuerySet,里面是元祖 7. order_by() --> 对查询结果排序 8. reverse() --> 对一个有序的查询结果集做反转 9. distinct() --> 去重,跨表查询时去掉重复的记录,MySQL不支持按字段去重 10. count() --> 返回数据条数 11. first() --> 取第一个数据 12. last() --> 取最后一条数据 13. exists() --> 判断表里有没有数据 分类: 1. 返回QuerySet列表的有哪一些? 1. all() 2. filter() 3. exclude() 4. order_by() 5. reverse() 6. distinct() 7. values('字段名', ...) --> 查询结果的列表里,都是字典 8. values_list(字段名', ...) --> 查询结果的列表里,都是元祖 2. 返回具体对象的 1. first() 2. last() 3. get() 3. 返回数字的 1. count() 4. 返回布尔值 1. exists() 4. 单表查询神奇的双下划线 查询操作:https://www.cnblogs.com/liwenzhou/p/8660826.html 1. 外键 ForeignKey 通过Foreignkey字段 ,能够得到和我关联的那个对象 数据库中保存的字段名是 外键字段_id 2. 外键增删改查 3. 跨表查询 1. 基于对象的查询 1. 正向查 2. 反向查 2. 基于QuerySet的查询 1. 正向查 2. 反向查 8. cookie&session:https://www.cnblogs.com/liwenzhou/p/8343243.html 1. Cookie 1. 是什么? 保存在浏览器端的键值对! 服务端在返回响应的时候,告诉浏览器保存的键值对!浏览器可以拒绝保存Cookie. 2. 为什么要有cookie? HTTP请求是无状态的,我们需要保存状态 --> cookie 3. Django中cookie的使用 1. 设置cookie rep = HttpResponse("ok") rep.set_cookie("key", "value", max_age=xx秒) rep.set_signed_cookie("key", "value", salt="ooxx", max_age=xx秒) 2. 获取cookie request.COOKIES.get("key") request.get_signed_cookie("key", default="", salt="ooxx") 3. cookie有失效时间 1. Django中不设置,关闭浏览器就失效了 2. 通过max_age设置超时时间 4. 补充3点: 1. 如何登陆后再跳转回之前访问的页面 --> next参数实现 2. 如何将FBV的装饰器应用到CBV上 --> from django.utils.decorators import method_decorator 3. 装饰器修复技术 --> from functools import wraps 2. session 1. 保存在服务端的键值对! 下周讲! 2. 练习题: 1. django请求生命周期 2. values和values_list的区别? 3. session和cookie是什么?以及区别? 4. django路由系统中name的作用? 5. filter和exclude的区别? 6. ORM查询示例: 表结构: 出版社表: ID 名称 图书表: ID 书名称 价格 出版社ID 题目: 1. 查询老男孩出版社出版过的价格大于200的书籍 2. 查询所有以py开头的书籍名称 3. 查询价格为50,100或者150的所有书籍名称及其出版社名称 4. 查询价格在100到200之间的所有书籍名称及其价格 5. 查询所有人民出版社出版的书籍的价格(从高到低排序,去重) 6. 查询价格大于200的书籍的个数 7. 查询价格不等于100的所有书籍 3. 作业:主机管理【02】:主机管理 1. 基于django创建表: 用户表:ID、用户名、密码 业务线表:ID、名称 主机表:ID、主机名、密码、业务线ID 2. 主机管理:增删改查(一对多,不需要做业务线管理,只要在数据库录入业务线数据即可) 3. 使用母板和动态路由 4. 套用BootStrap样式 采分点: 练习题:20 实现所有功能:70 代码写的清晰、健壮、可扩展:10
sqlite3文件数据库,点开即可使用
sqlite3数据库添加时间类型 可能有问题。
urls---views(写函数)----html
一、路由系统
1.Django的路由系统;用户请求与url'内容中是否匹配
2.正则表达式
动态匹配路由的方式传参数
分组匹配------------^edit_publisher/(\d+)/$
url(r'^admin/', admin.site.urls), url(r'^publisher_list/$', views.publisher_list, name="alex"), url(r'^edit_publisher/(?P\d+)/$ ', views.EditPublisher.as_view(), name="alex"),
def edit_publisher(request): if request.method == "POST": # 接收用户提交过来的数据 edit_id = request.POST.get("id") new_name = request.POST.get("name888") # 去数据库修改出版社名字 obj = models.Publisher.objects.get(id=edit_id) obj.name = new_name obj.save() return redirect("/publisher_list/") # 取url携带的参数 print(request.GET.get("id")) edit_id = request.GET.get("id") # 去数据库找编辑的出版社 publisher_obj = models.Publisher.objects.get(id=edit_id) return render(request, "edit_publisher.html", {"obj": publisher_obj})
def edit_publisher(request, edit_id): print(reverse('alex')) print("=" * 120) if request.method == "POST": new_name = request.POST.get("name888") # 去数据库修改出版社名字 obj = models.Publisher.objects.get(id=edit_id) obj.name = new_name obj.save() return redirect(reverse('alex')) print(edit_id) publisher_obj = models.Publisher.objects.get(id=edit_id) return render(request, "edit_publisher.html", {"obj": publisher_obj})
分组命名匹配---^edit_publisher/(?P\d+)/$
分组匹配:
相当于给视图函数传递 位置参数
分组命名匹配:
相当于给视图函数传递 关键字参数
?P给分组取一个名字 将捕获的值当成关键字参数传入
修改list html中a标签编辑、删除取值路径
reverse
# CBV class EditPublisher(views.View): def get(self, request, edit_id): publisher_obj = models.Publisher.objects.get(id=edit_id) return render(request, "edit_publisher.html", {"obj": publisher_obj}) def post(self, request, edit_id): new_name = request.POST.get("name888") # 去数据库修改出版社名字 obj = models.Publisher.objects.get(id=edit_id) obj.name = new_name obj.save() return redirect(reverse('alex'))
二、视图函数
1.import views 是dj中自带的函数
cbv views.类名.as_view()
2,dj上传文件 ,
1. 前端页面
1. form表单一定要有action,method必须是post
2. 一定要配置enctype="multipart/form-data
2.后端:chunks()不写也可实现功能,此功能是django提供的方法,一般写上。
# Django上传文件示例 class Upload(views.View): def get(self, request): return render(request, "upload.html") def post(self, request): # 拿到用户发送的文件数据 file_obj = request.FILES.get("code") # 保存下来 # 1. 拿到用户上传的文件名 filename = file_obj.name # 2. 在服务端创建一个同名的文件 with open(filename, "wb") as f: # 3. 从用户上传的文件对象中一点一点读数据,往我本地创建的文件句柄里一点一点写 for i in file_obj.chunks(): f.write(i) return HttpResponse("上传成功!")
"en"> "UTF-8">上传文件
json格式的数据---类似于{‘code’:0,'data':'alex'}
from django.http import JsonResponse
# 返回JSON格式数据 class JsonTest(views.View): def get(self, request): res = {"code": 0, "data": "alex"} res2 = ["alex", "污Sir", "金老板", "小姨妈", "MJJ"] # 1. 先将字典序列化成json格式的字符串 # import json # s = json.dumps(res2, ensure_ascii=False) #ensure_ascii=False确保输出汉字 # return HttpResponse(s) return JsonResponse(res2, safe=False) # 列表类型要写safe=False
xss攻击(跨站脚本攻击) : js代码--死循环
三、模板引擎
1. {{ }} --> 跟变量相关的操作
2. {% %} --> 跟逻辑相关的操作
{% for teacher in data %} {% if forloop.last %} {{ teacher }} {% else %} {{ teacher }}, {% endif %} {% endfor %}
4. 显示真正的html代码
{{ link|safe }}
import datetime now = datetime.datetime.now() print(now, type(now)) ret = now.strftime("%Y-%m-%d %H:%M:%S") # 日期类型转换为字符串类型 print(ret, type(ret))
模板语言不支持连续判断
不支持:{#{% if 3 > 2 > 1 %}{% endif %}
#}
需要这样写:{#{% if 3 > 2 and 2 > 1 %}{% endif %}
#}
默认找属性,属性优先级大于方法
# 测试模板语法 def template_test(request): data = ["金老板", "景女神", "MJJ"] # data = "" filesize = 1234567890 import datetime today = datetime.datetime.today() link = "" class Person(object): def __init__(self, name, dream): self.name = name self.dream = dream def dream(self): return "我的梦想是学好Python!" pw = Person("彭玮", "不去下一期!") return render(request, "t.html", { "data": data, "file_size": filesize, "today": today, "link": link, "person": pw })
"en"> "UTF-8">Title {#{{ data.1 }}
#}{{ data|default:"暂无数据" }}
{##管道符前后及冒号前后不要加空格#}{{ file_size|filesizeformat }}
{{ today }}
{#年月日时分秒#}{{ today|date:"Y-m-d H:i:s"}}
{{ link }}
{#加safe允许显示html及频繁弹出框#} {#{{ link|safe }}
#}
{% for teacher in data %} {# 最后一次循环,不加,#} {% if forloop.last %} {{ teacher }} {% else %} {{ teacher }}, {% endif %} {% endfor %}
{#{% if 3 > 2 > 1 %}{% endif %}
#} {##} {#{% if 3 > 2 and 2 > 1 %}{% endif %}
#}
{{ person.name }} {{ person.dream }}
四、母版
bt--css jquery--js
怎么使用?
1. 在子页面 通过使用 {% extends ‘模板名’ %} --> 放在子页面的最上面
2. {% block xx %}{% endblock %}
"en"> "UTF-8">{{ html_title }} "stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css"> {% block page-css %} {% endblock %} {% include 'nav.html' %}class="container">{% block page-js %} {% endblock %}class="row">class="col-md-8 col-md-offset-2"> {% block page-main %} {% endblock %}
{% extends 'mama.html' %} {% block page-main %}
# | id | 出版社名称 | 操作 |
---|---|---|---|
{{ forloop.counter }} | {{ publisher.id }} | {{ publisher.name }} | "/edit_publisher/{{ publisher.id }}/" class="btn btn-info">编辑 "/delete_publisher/" class="btn btn-danger">删除 |
3. 组件
把单独的一段html代码放在一个文件
使用 {% include '组件名' %}导入
五.跨站请求伪造 CSRF
网站无法限制谁给他发请求,例如:自己写的页面也可跳转到sougouweb。
钓鱼网站 往银行发请求,获取你的用户名、密码等信息。
value="随机的字符串"
"en"> "UTF-8">Title
def csrf_test(request): if request.method == "POST": print(request.POST) return HttpResponse("OK") return render(request, "csrf_test.html")
"en"> "UTF-8">Title
六、ORM单表查询13条+外键操作(一对多)
1.字段和参数
1. 字段 1. CharField 2. AutoField 3. DateField 4. DateTimeField() 5. IntergeField() 2. 参数 1. null=True 2. default=默认值 3. unique=True 4. 时间字段 1. auto_now_add=True 第一次创建时 2. auto_add=True 每次更新时
AutoField(Field) - int自增列,必须填入参数 primary_key=True BigAutoField(AutoField) - bigint自增列,必须填入参数 primary_key=True 注:当model中如果没有自增列,则自动会创建一个列名为id的列 from django.db import models class UserInfo(models.Model): # 自动创建一个列名为id的且为自增的整数列 username = models.CharField(max_length=32) class Group(models.Model): # 自定义自增列 nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) SmallIntegerField(IntegerField): - 小整数 -32768 ~ 32767 PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField) - 正小整数 0 ~ 32767 IntegerField(Field) - 整数列(有符号的) -2147483648 ~ 2147483647 PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField) - 正整数 0 ~ 2147483647 BigIntegerField(IntegerField): - 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807 BooleanField(Field) - 布尔值类型 NullBooleanField(Field): - 可以为空的布尔值 CharField(Field) - 字符类型 - 必须提供max_length参数, max_length表示字符长度 TextField(Field) - 文本类型 EmailField(CharField): - 字符串类型,Django Admin以及ModelForm中提供验证机制 IPAddressField(Field) - 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制 GenericIPAddressField(Field) - 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6 - 参数: protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6" unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启此功能,需要protocol="both" URLField(CharField) - 字符串类型,Django Admin以及ModelForm中提供验证 URL SlugField(CharField) - 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号) CommaSeparatedIntegerField(CharField) - 字符串类型,格式必须为逗号分割的数字 UUIDField(Field) - 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证 FilePathField(Field) - 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能 - 参数: path, 文件夹路径 match=None, 正则匹配 recursive=False, 递归下面的文件夹 allow_files=True, 允许文件 allow_folders=False, 允许文件夹 FileField(Field) - 字符串,路径保存在数据库,文件上传到指定目录 - 参数: upload_to = "" 上传文件的保存路径 storage = None 存储组件,默认django.core.files.storage.FileSystemStorage ImageField(FileField) - 字符串,路径保存在数据库,文件上传到指定目录 - 参数: upload_to = "" 上传文件的保存路径 storage = None 存储组件,默认django.core.files.storage.FileSystemStorage width_field=None, 上传图片的高度保存的数据库字段名(字符串) height_field=None 上传图片的宽度保存的数据库字段名(字符串) DateTimeField(DateField) - 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] DateField(DateTimeCheckMixin, Field) - 日期格式 YYYY-MM-DD TimeField(DateTimeCheckMixin, Field) - 时间格式 HH:MM[:ss[.uuuuuu]] DurationField(Field) - 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型 FloatField(Field) - 浮点型 DecimalField(Field) - 10进制小数 - 参数: max_digits,小数总长度 decimal_places,小数位长度 BinaryField(Field) - 二进制类型 字段合集
以下内容参考博客地址:https://www.cnblogs.com/liwenzhou/p/8660826.html
2.ORM必知必会单表查询13条
1. all() --> 查询所有结果 2. filter() --> 根据查询条件查询数据库的 3. get() --> 获取一个唯一的值 4. exclude() --> 将符合条件的都剔除掉,留下不符合条件的 5. values('字段名', ...) --> 返回一个QuerySet,里面是字典 6. values_list(字段名', ...) --> 返回一个QuerySet,里面是元祖 7. order_by() --> 对查询结果排序 8. reverse() --> 对一个有序的查询结果集做反转 9. distinct() --> 去重,跨表查询时去掉重复的记录,MySQL不支持按字段去重 10. count() --> 返回数据条数 11. first() --> 取第一个数据 12. last() --> 取最后一条数据 13. exists() --> 判断表里有没有数据
# 如何在一个py文件中 使用Django项目的相关配置或内容 import os if __name__ == '__main__': os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") # manage.py中第6行 import django django.setup() from app01 import models # 查询age=18的第一个人 # ret = models.Person.objects.get(age=18) # pk(主键) unique # print(ret) # 查询age=18的所有人 # ret = models.Person.objects.filter(age=18) #获取的是对象的列表,多个值 # print(ret[0]) # ret[0]取一个值 # ret = models.Person.objects.filter(age=18).values("age", "phone") # print(ret) # 打印指定的两个字段,字典内容 # ret = models.Person.objects.filter(age=18).values_list("age", "phone") # print(ret) # 打印指定的两个字段,小元组内容,只有值,无key了 # 排序 # ret = models.Person.objects.all().order_by("age") # print(ret) # 神奇的双下划线 # 查询年龄大于18岁的 # ret = models.Person.objects.filter(age__gt=18, id__gt=1) # print(ret) # 查询id值在 [1, 2]的人 # ret = models.Person.objects.filter(id__in=[1, 2, 20000]) # print(ret) # 取1,2的人,不会报错 # # 查询id值不在[1,2]的人 # ret = models.Person.objects.exclude(id__in=[1,2]) # print(ret) # 查询名字中包含 JJ 的那个人 # ret = models.Person.objects.filter(name__contains="JJ") # print(ret) # 不区分大小写查询 # ret = models.Person.objects.filter(name__icontains="jj") # print(ret) # 查询id在1-3区间内的数据 # ret = models.Person.objects.filter(id__range=[1, 3]) # print(ret) # 查询以JJ结尾的人 # ret = models.Person.objects.filter(name__endswith='JJ') # print(ret) # print(models.Person.objects.first().birthday) #sqlite3中显示None,日期的格式有问题,mysql可以显示 # 查询 生日 是 2018年的所有人 # ret = models.Person.objects.filter(birthday__year=2018) # print(ret) #外键 # 查询第一本书关联的出版社的名字 # 1. 基于对象的查询 # book_obj = models.Book.objects.first() # ret = book_obj.publisher.name # print(ret) # 2. 基于queryset的双下划线查询,双下划线表示跨表 # ret = models.Book.objects.all().values_list("publisher__name").distinct() # print(ret) # 反向查询 # 1. 由出版社反向查询书籍(基于对象的查询) # publisher_obj = models.Publisher.objects.get(id=2) # 找到张江出版社 # 张江出版社出版的所有书籍 # ret = publisher_obj.book_set.all() # print(ret) # 2. 基于queryset的双下划线 # 江出版社出版的所有书籍的书名 ret = models.Publisher.objects.filter(id=2).values_list("book__title") print(ret)
注:
查询:
1.根据唯一值查询:用get
2.一般会用filter
1256789 11 12 常用
id__gt=1 #id大于1的数据
分类: 1. 返回QuerySet列表的有哪一些? 1. all() 2. filter() 3. exclude() 4. order_by() 5. reverse() 6. distinct() 7. values('字段名', ...) --> 查询结果的列表里,都是字典 8. values_list(字段名', ...) --> 查询结果的列表里,都是元祖 2. 返回具体对象的 1. first() 2. last() 3. get() 3. 返回数字的 1. count() 4. 返回布尔值 1. exists()
不同的对象有不同的方法,可以根据对象调用方法。返回QuerySet的使用加[0]
3. 单表查询神奇的双下划线
models.Tb1.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值 models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据 models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in models.Tb1.objects.filter(name__contains="ven") # 获取name字段包含"ven"的 models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感 models.Tb1.objects.filter(id__range=[1, 3]) # id范围是1到3的,等价于SQL的bettwen and 类似的还有:startswith,istartswith, endswith, iendswith date字段还可以: models.Class.objects.filter(first_day__year=2017)
4.外键操作--重点!
通过Foreignkey字段 ,能够得到和我关联的那个对象,例如: book.publisher.name
一对多--外键操作
外键关联--查、增删、改
关联字段__被查名称 可以跨表查询
基于例子练习跨表查询(正向、反向),例子见上 orm_test.py或如下
#外键 # 查询第一本书关联的出版社的名字 # 1. 基于对象的查询 # book_obj = models.Book.objects.first() # ret = book_obj.publisher.name # print(ret) # 2. 基于queryset的双下划线查询,双下划线表示跨表 # ret = models.Book.objects.all().values_list("publisher__name").distinct() #所有书籍出版社的名字 # ret = models.Book.objects.filter(id=1).values_list("publisher__name")#id为1的书籍出版社的名字 # print(ret) # 反向查询 # 1. 由出版社反向查询书籍(基于对象的查询) # publisher_obj = models.Publisher.objects.get(id=2) # 找到张江出版社 # 张江出版社出版的所有书籍 # ret = publisher_obj.book_set.all() # print(ret) # 2. 基于queryset的双下划线 # 江出版社出版的所有书籍的书名 ret = models.Publisher.objects.filter(id=2).values_list("book__title") print(ret)
from django.db import models # Create your models here. class Publisher(models.Model): name = models.CharField(max_length=12) # 书籍表 class Book(models.Model): title = models.CharField(max_length=32) publisher = models.ForeignKey(to="Publisher", on_delete=models.CASCADE) #on_delete级联删除 class Person(models.Model): name = models.CharField(max_length=12, default="alex") age = models.IntegerField(default=18) birthday = models.DateField() birthday2 = models.DateTimeField(null=True) phone = models.CharField(max_length=11, unique=True) # 创建该记录时自动把当前时间保存到该字段 join_date = models.DateField(auto_now_add=True) # 更新该记录的值时 自动把当前时间保存到该字段 last_date = models.DateField(auto_now=True) def __str__(self): return "{}-{}".format(self.age, self.phone)
from django.conf.urls import url from django.contrib import admin from app01 import views # from django.urls import path urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^publisher_list/$', views.publisher_list, name="alex"), url(r'^edit_publisher/(?P\d+)/$ ', views.EditPublisher.as_view(), name="alex"), # 测试上传你文件 url(r'^upload/$', views.Upload.as_view()), # 测试返回Json格式数据 url(r'^json_test/$', views.JsonTest.as_view()), # 测试模板语法 url(r'^template_test/$', views.template_test), # 测试跨站请求伪造 (CSRF) url(r'^csrf_test/$', views.csrf_test), url(r'^book_list/$', views.book_list), url(r'^add_book/$', views.AddBook.as_view()), url(r'^delete_book/(?P\d+)/$ ', views.DeleteBook.as_view()), url(r'^edit_book/(?P\d+)/$ ', views.EditBook.as_view()), url(r'^login/$', views.login), ]
@login_check def book_list(request): # 去数据库查询所有的书籍 data = models.Book.objects.all() return render(request, "book_list.html", {"book_list": data}) class AddBook(views.View): @method_decorator(login_check) def get(self, request): data = models.Publisher.objects.all() return render(request, "add_book.html", {"publisher_list": data}) def post(self, request): book_name = request.POST.get("title") publisher_id = request.POST.get("publisher") # publisher_obj = models.Publisher.objects.get(id=publisher_id) # 创建书籍 models.Book.objects.create( title=book_name, publisher_id=publisher_id # publisher=publisher_obj #麻烦,不推荐 ) return redirect("/book_list/") class DeleteBook(views.View): def get(self, request, pk): models.Book.objects.filter(id=pk).delete() return redirect("/book_list/") class EditBook(views.View): def get(self, request, pk): book_obj = models.Book.objects.get(id=pk) publisher_list = models.Publisher.objects.all() return render(request, "edit_book.html", {"book": book_obj, "publisher_list": publisher_list}) def post(self, request, pk): book_obj = models.Book.objects.get(id=pk) new_title = request.POST.get("title") new_publisher_id = request.POST.get("publisher") # 更新 book_obj.title = new_title book_obj.publisher_id = new_publisher_id # 同步到数据库 book_obj.save() return redirect("/book_list/")
"en"> "UTF-8">编辑书籍
# 登录 def login(request): if request.method == "POST": next = request.GET.get("next") username = request.POST.get("username") pwd = request.POST.get("pwd") if username == "alex" and pwd == "alexdsb": if next: rep = redirect(next) else: rep = redirect("/publisher_list/") # 在返回响应的时候 告诉浏览器保存我指定的键值对(cookie) # rep.set_cookie("s21", "hao", max_age=7) # 7秒钟有效的Cookie rep.set_signed_cookie("s21", "hao", salt="ooxx", max_age=7) # 设置加盐的cookie return rep else: return HttpResponse("滚~") return render(request, "login.html") # 装饰器版本登录认证 def login_check(func): @wraps(func) def inner(request, *args, **kwargs): next = request.path_info # 登录验证 # v = request.COOKIES.get("s21") # 取正常的cookie v = request.get_signed_cookie("s21", default="", salt="ooxx") # 获取加盐的cookie if v == "hao": return func(request, *args, **kwargs) else: return redirect("/login/?next={}".format(next)) return inner
七、cookie和session
浏览器可以拒绝保存Cookie.在浏览器的settings中搜索cookie,禁用即可!
补充3点:
1. 如何登陆后再跳转回之前访问的页面 --> next参数实现
2. 如何将FBV的装饰器应用到CBV上 --> from django.utils.decorators import method_decorator
3. 装饰器修复技术 --> from functools import wraps
form表单中的action不要写死 ,应是
# 登录 def login(request): if request.method == "POST": next = request.GET.get("next") username = request.POST.get("username") pwd = request.POST.get("pwd") if username == "alex" and pwd == "alexdsb": if next: rep = redirect(next) else: rep = redirect("/publisher_list/") # 在返回响应的时候 告诉浏览器保存我指定的键值对(cookie) # rep.set_cookie("s21", "hao", max_age=7) # 7秒钟有效的Cookie rep.set_signed_cookie("s21", "hao", salt="ooxx", max_age=7) # 设置加盐的cookie return rep else: return HttpResponse("滚~") return render(request, "login.html") #使用 def publisher_list(request): # 从请求中找有没有我之前登录时候保存的特殊的键值对 print(request.COOKIES) v = request.COOKIES.get("s21") # 如果你请求携带的值 和我之前让你保存的是同一个,就表示你是已经登陆过的用户,默认放行 if v == "hao": print(request.path_info) data = models.Publisher.objects.all() return render(request, "publisher_list.html", {"publisher_list": data}) else: return redirect("/login/")
# 装饰器版本登录认证 def login_check(func): @wraps(func) #装饰器修复技术 def inner(request, *args, **kwargs): next = request.path_info # 获取当前路径 # 登录验证 # v = request.COOKIES.get("s21") # 取正常的cookie v = request.get_signed_cookie("s21", default="", salt="ooxx") # 获取加盐的cookie if v == "hao": return func(request, *args, **kwargs) # 你要执行的视图函数 else: return redirect("/login/?next={}".format(next)) return inner # 登录 def login(request): if request.method == "POST": next = request.GET.get("next") username = request.POST.get("username") pwd = request.POST.get("pwd") if username == "alex" and pwd == "alexdsb": if next: rep = redirect(next) else: rep = redirect("/publisher_list/") # 在返回响应的时候 告诉浏览器保存我指定的键值对(cookie) # rep.set_cookie("s21", "hao", max_age=7) # 7秒钟有效的Cookie rep.set_signed_cookie("s21", "hao", salt="ooxx", max_age=7) # 设置加盐的cookie return rep else: return HttpResponse("滚~") return render(request, "login.html")
@login_check def book_list(request): # 去数据库查询所有的书籍 data = models.Book.objects.all() return render(request, "book_list.html", {"book_list": data}) from django.utils.decorators import method_decorator class AddBook(views.View): @method_decorator(login_check) def get(self, request): data = models.Publisher.objects.all() return render(request, "add_book.html", {"publisher_list": data}) def post(self, request): book_name = request.POST.get("title") publisher_id = request.POST.get("publisher") # publisher_obj = models.Publisher.objects.get(id=publisher_id) # 创建书籍 models.Book.objects.create( title=book_name, publisher_id=publisher_id # publisher=publisher_obj #麻烦,不推荐 ) return redirect("/book_list/")
装饰器修复技术---@warppers
--动态添加功能+显示被装饰函数信息
from functools import wraps def wrapper(func): @wraps(func) # 借助内置的工具修复被装饰的函数 def inner(*args, **kwargs): print("呵呵") func(*args, **kwargs) return inner @wrapper def foo(arg): """ 这是一个测试装饰器的函数 :param arg: int 必须是int类型 :return: None """ print("嘿嘿嘿" * arg) foo(10) print(foo.__doc__)