[a-zA-Z]{2})/$"
def fun(request,year,month) 要明确变量
def fun(request,**kwargs) 也可 接收到kwargs为{"year":xx,"month":yy}
注意不能混用,若month不写,后边分组匹配不到
多个路径对应一个函数:通常适用于 无参时访问第一页,有参访问对应页面
def fun(res,id="1"):指定默认值即可
app中建立app01_urls.py 名字无规定
import django.urls import url
urlpatterns=[] 必须有这个属性
在主urls中导入
from ... import app01_urls
urlpattrens=[
...
url(r"^app01/",include(urls)) # 所有以app01开头的 分流
]
查找时 /app01/xx/yy 注意为r"^app01",后边没有"/" 会报错
注:url(xxx,yy,{"age":18}) 对应的yy函数 使用def yy(req,age)
可以传参,但不常用
"""
# 页面之间跳转的时候 不能写死跳转路径:反向解析 ->通过别名方式
# 命名url与url解析:urlpattern中的url会发生变化,html中写死了
# url(xx,yy,name="zzz") 此时html中 写 href="{url 'zzz'}" 相当于xxx 即可跳转到yy函数
# 若在函数中跳转,也不能写死
# from django.urls import reverse
# analysis_url=reverse("zzz")
# return redirect(analysis_url)
# 注意对于传参数的url 需要传参数
# reverse("zzz",kwargs={"xx":1,"yy":2}) 当分组有别名时字典传入,若不是 args=(..) 元祖传入即可
# {% url 'zzz' arg1 arg2 ...%}
# 在不同的app中了能会出现相同的别名
# 可以再父urls中 url(xx,include(app01_urls.py,namespace="app01"))
# html {% url 'app01:zzz'%} 找到app01 里面的别名zzz
# ==========================================
# orm 配合 路由系统
"""
1,不同的表的删除,可以使用一个方法:
url(r"^delete/([a-zA-Z]+)/(\d)/$",delete) 传递表名,id
对于比较长的正则,可以建文件夹,编译 r = re.complie(xxx),再引入即可
2,def fun(res,arg1,arg2):
hasttr(py文件,"xxx") getattr(py文件,"xxx")得到目标
if hasattr(modules,arg1.capitalized()) 首字母打大写
cls = get....
cls.Object.get(id=arg2).delete try本句
"""
# ==========================================
# orm常用字段 charfiled 对应varchar,没有固定长度的字段,可自定义
"""
class FixedCharField(models.Field):
自定义的char类型的字段类
def __init__(self, max_length, *args, **kwargs):
self.max_length = max_length
super(FixedCharField, self).__init__(max_length=max_length, *args, **kwargs)
def db_type(self, connection):
限定生成数据库表的字段类型为char,长度为max_length指定的值
return 'char(%s)' % self.max_length
class Person(models.Model):
name = models.CharField(max_length=32)
new_name = FixedCharField(max_length=64, default="张三") # char(64)
age = models.IntegerField(default=18)
birthday = models.DateField(auto_now_add=True)
def __str__(self):
return self.name
class Meta:
db_table = "person" 指明 生成的数据库名
"""
# 1,AutoField int自增列,必须primary_key=True,若没有自增列,会自动创建id自增列
# 2,IntegerField 整数范围 21亿那个
# 3,CharField 必须max_length, 指定长度
# 4,DateTimeField 相当于datetime模块
# yyyy-mm-dd hh:MM[:ss[.uuuuu]][TZ]
# 5,DateField
# auto_now_add=True 创建记录时会添加当前是时间,不用写default
# auto_now=True 每次更新记录时会更新该字段
# 不常用字段
# BigAutoField,大整数
# SmallIntegerField 小整数 -32768-32767
# PositiveSmallIntegerField 正小整的 0-32767
# PositiveIntegerField 0-21亿
# BigIntegerField -922..... --- 922....
# BooleanFiled
# NullBooleanField 可为空的bool
# TextField 大文本
# EmailField 还是charfiled django做了校验
# IPAddressField 有验证
# GenericIPAddressField 支持ipv4,ipv6
# URLFiled charfiled 验证
# SlugFiled 字符串类型,字母数字下划线连字符等
# CommaSeparatedIntegerFiled 格式为逗号分割的数字
# UUIDField UUID验证
# TimeFiled
# DurationFiled 长整数,时间间隔orm中获取到的类型为datetime.timedel类型
# FloatField 浮点型
# DecimalField 10进制小数
# max_dights,小数总长度,decimal_places,小数位长度
# BinaryField 二进制数据
# =========================================
# 字段参数
# null 没写=True 表示不能为空
# unique
# db_index=true 表示为此字段设置索引
# default
# to 设置关联的表
# to_field="xxx" 设置关联的列 默认是id
# related_name 反向操作时使用的字段名,用于代替反向查询时的"表名_set"
# related_query_name 反向查询操作时,使用的链接前缀,用于替换表明
# on_delete 当删除关联表中的数据时,当前表与其的关联行为
# modules.Cascade 关联删除 默认的
# modules.DO_NOTHING 引发Integrity错误
# modules.PROJECT 引发protected错误
# modules.SET_NLL 关联的字段置位NULL(前提字段可空)
# modules.SET_DEFAULT 关联的字段为默认值(前提字段有默认值)
# modules.SET(func) 可自定义函数
# db_constraint=Flase 用上了外键,但是没有级联操作,
# 软外键:方法1,代码实现 方法2,db_constraint=Flase
# ======================================
# class Mate:
# db_table 重写表名
# index_together 联合索引 2列做索引
# unique_together 联合唯一索引 2列可以有一个重复,不能都重复
# ordering 指定an什么字段排序,设置了该属性,结果才可以reverse()
```
5_orm_1
=======
```
# ORM小练习 如何在一个Python脚本或文件中 加载Django项目的配置和变量信息
# 常用的查询方法
import os
if __name__ == '__main__':
# 加载Django项目的配置信息
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "ormday69.settings")
# 导入Django,并启动Django项目
import django
django.setup()
# from app_01 import models
# # 查询所有的人
# ret = models.Person.objects.all()
# # get查询
# ret = models.Person.objects.get(name="小黑") 只查询到 第一个
# # filter
# ret = models.Person.objects.filter(id=100) # 不存在返回一个空的QuerySet,不会报错
# # 就算查询的结果只有一个,返回的也是QuerySet,我们要用索引的方式取出第一个元素
# ret = models.Person.objects.filter(id=1)[0]
# print("exclude".center(80, "*")) # 占80个字符居中,*号填充
# # exclude
# ret = models.Person.objects.exclude(id=1) 反向查询 id!=1
# print("values".center(80, "*"))
# # values 返回一个QuerySet对象,里面都是字典。 不写字段名,默认查询所有字段
# ret = models.Person.objects.values("name", "birthday")
# print("values_list".center(80, "*"))
# # values_list 返回一个QuerySet对象,里面都是元祖。 不写字段名,直接写字段值,默认查询所有字段
# ret = models.Person.objects.values_list()
# print("order_by".center(80, "*"))
# # order_by 按照指定的字段排序
# ret = models.Person.objects.all().order_by("birthday")
# print("reverse".center(80, "*"))
# # reverse 将一个有序的QuerySet 反转顺序
# # 对有序的QuerySet才能调用reverse
# ret = models.Person.objects.all().reverse()
# print("count".center(80, "*"))
# # count 返回QuerySet中对象的数量
# ret = models.Person.objects.all().count()
# print("first".center(80, "*"))
# # first 返回QuerySet中第一个对象
# ret = models.Person.objects.all().first()
# print("last".center(80, "*"))
# # last 返回QuerySet中最后一个对象
# ret = models.Person.objects.all().last()
# print("exists".center(80, "*"))
# # exists 判断表里有没有数据
# ret = models.Book.objects.exists()
# print(ret)
# ===================================================
# 单表查询之神奇的双下划线
# # 查询id值大于1小于4的结果
# ret = models.Person.objects.filter(id__gt=1, id__lt=4)
# ===================================================
# # in
# # 查询 id 在 [1, 3, 5, 7]中的结果
# ret = models.Person.objects.filter(id__in=[1, 3, 5, 7])
# ret = models.Person.objects.exclude(id__in=[1, 3, 5, 7]) 等于not in
# ===================================================
# 模糊查询
# # contains 字段包含指定值的
# # icontains 忽略大小写包含指定值
# ret = models.Person.objects.filter(name__contains="小")
# isstartwith,startwith,endwith,isendwith
# ===================================================
# # range
# # 判断id值在 哪个区间的 SQL语句中的between and 1<= <=3
# ret = models.Person.objects.filter(id__range=[1,3])
# ===================================================
# # 日期和时间字段还可以有以下写法,按照日期中的某一项查询
# ret = models.Person.objects.filter(birthday__year=2000)
# ret = models.Person.objects.filter(birthday__year=2000, birthday__month=5)
# ===================================================
# 注意 obj得到的是对象,不能直接.value或value_list
# 外键的查询操作
# 正向查询,通过有外键字段的表查没得是正向
# 基于对象 跨表查询
# book_obj = models.Book.objects.all().first()
# ret = book_obj.publisher # 和我这本书关联的出版社对象
# ret = book_obj.publisher.name # 和我这本书关联的出版社对象
# 查询id是1的书的出版社的名称
# 利用双下划线 跨表查询
# 双下划线就表示跨了一张表
# ret = models.Book.objects.filter(id=1).values_list("publisher__name")或value
# =================================================================
# 反向查询
# 1. 基于对象查询
# publisher_obj = models.Publisher.objects.get(id=1) # 得到一个具体的对象
# # ret = publisher_obj.book_set.all() # 反向得到书的信息,默认是表名_set
# 建表时通过related_name="books"可更改
# ret = publisher_obj.books.all()
# # 2. 基于双下划线
# ret = models.Publisher.objects.filter(id=1).values_list("(related_query_name)__title")
# =================================================================
# 多对多
# 查询
# author_obj = models.Author.objects.first()
# print(author_obj.name)
# 查询金老板写过的书
# ret = author_obj.books.all() 前边学过 author_obj.books:关联管理器
# ==========================
# 1. create
# 通过作者创建一本书,会自动保存
# 做了两件事:
# 1. 在book表里面创建一本新书,2. 在作者和书的关系表中添加关联记录
# author_obj.books.create(title="金老板自传", publisher_id=2)
# =============
# 2. add
# 在金老板关联的书里面,再加一本id是4的书
# book_obj = models.Book.objects.get(id=4)
# author_obj.books.add(book_obj) # 加已经存在的书
# 添加多个
# book_objs = models.Book.objects.filter(id__gt=5)
# author_obj.books.add(*book_objs) # 要把列表打散再传进去
# 直接添加id
# author_obj.books.add(9)
# =======================================
# remove
# 从金老板关联的书里面把 开飞船 删掉
# book_obj = models.Book.objects.get(title="跟金老板学开飞船")
# author_obj.books.remove(book_obj)
# 从金老板关联的书里面把 id是8的记录 删掉
# author_obj.books.remove(8)
# =======================================
# clear
# 清空
# 把景女神 关联的所有书都删掉
# jing_obj = models.Author.objects.get(id=2)
# jing_obj.books.clear()
# =======================================
# 额外补充的,外键的反向操作
# 找到id是1的出版社
# publisher_obj = models.Publisher.objects.get(id=2)
# publisher_obj.books.clear() # 注意books的 外键是否可为空
# =================================================================
# 聚合
from django.db.models import Avg, Sum, Max, Min, Count
# ret = models.Book.objects.all().aggregate(price_avg=Avg("price"))
# print(ret) 返回字典{"price":xxx} 按price列指定, 可修改(k=Avg("price"))
# ret = models.Book.objects.all().aggregate(price_avg=Avg("price"), price_max=Max("price"), price_min=Min("price"))
# 也是字典返回
# print(ret.get("price_max"), type(ret.get("price_max")))
# =================================================================
# 分组查询
# 查询每一本书的作者个数
# ret = models.Book.objects.all().annotate(author_num=Count("author")) queryset 书对象
# # print(ret)
# for book in ret:
# print("书名:{},作者数量:{}".format(book.title, book.author_num)) # 书多了一个author_num属性
# 查询作者数量大于1的书
# ret = models.Book.objects.all().annotate(author_num=Count("author")).filter(author_num__gt=1)
# print(ret)
# 查询各个作者出的书的总价格
# ret = models.Author.objects.all().annotate(price_sum=Sum("books__price")).values_list("name", "price_sum")
# ret = models.Author.objects.all().annotate(price_sum=Sum("books__price"))
# print(ret)
# for i in ret:
# print(i, i.name, i.price_sum)
# print(ret.values_list("id", "name", "price_sum")) 与for类似
# =================================================================
# F(两个字段作比较)和Q
# ret = models.Book.objects.filter(price__gt=9.99)
# print(ret)
# 查询出 库存数 大于 卖出数的 所有书(两个字段做比较)
from django.db.models import F
# ret = models.Book.objects.filter(kucun__gt=F("maichu"))
# =================================================================
# 刷单 把每一本书的卖出数都乘以3
# obj = models.Book.objects.first()
# obj.maichu = 1000 * 3
# obj.save() 只修改一个对象
# 具体的对象没有update(),QuerySet对象才有update()方法。
# models.Book.objects.update(maichu=F("maichu")*3) 全都修改了
# 给每一本书的书名后面加上 第一版
# from django.db.models.functions import Concat
# from django.db.models import Value
# 修改字符串
# models.Book.objects.update(title=Concat(F("title"), Value("第一版")))
# Q查询
from django.db.models import Q
# 查询 卖出数大于1000,并且 价格小于100的所有书
# ret = models.Book.objects.filter(maichu__gt=1000, price__lt=100) # 并且
# print(ret)
# 查询 卖出数大于1000,或者 价格小于100的所有书
# ret = models.Book.objects.filter(Q(maichu__gt=1000) | Q(price__lt=100))
# print(ret)
# Q查询和字段查询同时存在时, 字段查询要放在Q查询的后面 后边的与前边是 与的关系
# ret = models.Book.objects.filter(Q(maichu__gt=1000) | Q(price__lt=100), title__contains="金老板")
# print(ret)
# Django ORM 事务
# try:
# from django.db import transaction
#
# with transaction.atomic(): # 加入事务
# # 先创建一个出版社
# new_publisher = models.Publisher.objects.create(name="火星出版社")
# # 创建一本书
# models.Book.objects.create(
# title="橘子物语",
# price=11.11,
# kucun=10,
# maichu=10,
# publisher_id=1000 # 指定一个不存在的出版社id
# )
# except Exception as e:
# print(str(e))
# 没有指定原子操作
# try:
#
# # 先创建一个出版社
# new_publisher = models.Publisher.objects.create(name="火星出版社")
# # 创建一本书
# models.Book.objects.create(
# title="橘子物语",
# price=11.11,
# kucun=10,
# maichu=10,
# publisher_id=1000 # 指定一个不存在的出版社id
# )
# except Exception as e:
# print(str(e))
# 执行原生SQL
# 更高灵活度的方式执行原生SQL语句
# from django.db import connection
# cursor = connection.cursor() # cursor = connections['default'].cursor()
# cursor.execute("SELECT * from app01_book where id = %s", [1])
# ret = cursor.fetchone()
# print(ret)
# 在QuerSet查询的基础上自己指定其他的SQL语句(了解即可)
ret = models.Book.objects.extra(
# 把出版社计数 赋值给newid
select={'newid': 'select count(1) from app01_publisher where id>%s'},
select_params=[1, ],
where=["app01_book.id=%s"],
params=[1, ],
tables=['app01_publisher']
)
print(ret)
for i in ret:
print(i)
```
6_orm_2
=======
```
# orm一对一:
# 当一个表中属性过多的时候,将属性分开,分为常用的属性表,和不常用的
# 例如第三方登录时,常请求的用户名,密码,而爱好,身份证号等不常用信息,可存放在另一张表中
# 构成一对一关系
"""
class A(model.Model):
...
detail=models.OneToOneField(to="B") 逐数据库中 列名为detail_id
class B(models.Model):
...若没有主键会自动创建id列
通过A获取B a = models.A.objects.get(id=1) b = a.deatil b.xxx可获取属性
"""
# orm多对多:
# 1,自动创建第三张表
# 2,自己创建
""" 自己创建第三张表 查询比较慢,不能使用author.books了
class Author_Book(model.Model):
...
author = modelsForeignKey("Author") author_id
book = modelsForeignKey("Book) book_id
查询时,手动经
过第三张表查询
"""
# 3,自己创建表,但使用ManyToMany
"""
第三张表的建立与2相同
class Author():
...
books = models.ManyToMany(to="Book",throuth="第三张表",throght_fields=(author,book))
里边是元祖,顺序固定,应为是在author中 所以先写author(第三张表中的author)
注意第三张表 class Meta:
unique_tgether = ("author","book")
"""
# 第三张表无其他字段,第一种
# 有其他字段:第三种 如聊天记录,不仅要双方那个id,还有时间,内容.... 因此需要自己创建
# 使用第三种方法时,是没有add方法,remove()方法等
# 例:给作者1加一本书 obj.get(id=1).books.add(xxx) 第一种
# 第三种:直接添加记录
# 反查有book查author ...filter(id=1).value("related__name__author的属性")
# ===========================================
# csfr 跨站请求伪造 服务器返回给用户一个html页面,里面有form表单 action="xxxx"
# 此时即可得到xxxx请求地址, 即可自定义html,form添加其他input 请求服务器,即跨站请求伪造
# 解决方案:服务器返回的html中有一项input name=key value="每个用户不同,或每次请求不同",以此识别用户
# 默认是开启的, 即不能跨站请求,弱不需要注释即可
"""
使用方法:在form中 {% csrf_token%} 在html中会变为
若出现跨站请求即会禁止 一般就是403
在render中 生成html时,会自动产生key,通过Post接受参数时,会自动校验,不通过即拒绝
"""
```
7_分页_session_cookies
====================
```
# 分页
class Page():
def __init__(self, page_num, total_count, url_prefix, per_page=10, max_page=11):
"""
:param page_num: 当前页码数
:param total_count: 数据总数
:param url_prefix: a标签href的前缀
:param per_page: 每页显示多少条数据
:param max_page: 页面上最多显示几个页码
"""
self.url_prefix = url_prefix
self.max_page = max_page
# 每一页显示多少条数据
# 总共需要多少页码来展示
total_page, m = divmod(total_count, per_page)
if m:
total_page += 1
self.total_page = total_page
try:
page_num = int(page_num)
# 如果输入的页码数超过了最大的页码数,默认返回最后一页
if page_num > total_page:
page_num = total_page
except Exception as e:
# 当输入的页码不是正经数字的时候 默认返回第一页的数据
page_num = 1
self.page_num = page_num
# 定义两个变量保存数据从哪儿取到哪儿
self.data_start = (page_num - 1) * 10
self.data_end = page_num * 10
# 页面上总共展示多少页码
if total_page < self.max_page:
self.max_page = total_page
half_max_page = self.max_page // 2
# 页面上展示的页码从哪儿开始
page_start = page_num - half_max_page
# 页面上展示的页码到哪儿结束
page_end = page_num + half_max_page
# 如果当前页减一半 比1还小
if page_start <= 1:
page_start = 1
page_end = self.max_page
# 如果 当前页 加 一半 比总页码数还大
if page_end >= total_page:
page_end = total_page
page_start = total_page - self.max_page + 1
self.page_start = page_start
self.page_end = page_end
@property
def start(self):
return self.data_start
@property
def end(self):
return self.data_end
def page_html(self):
# 自己拼接分页的HTML代码
html_str_list = []
# 加上第一页
html_str_list.append('首页'.format( self.url_prefix))
# 判断一下 如果是第一页,就没有上一页
if self.page_num <= 1:
html_str_list.append('<<'.format(self.page_num-1))
else:
# 加一个上一页的标签
html_str_list.append('<<'.format( self.url_prefix, self.page_num-1))
for i in range(self.page_start, self.page_end+1):
# 如果是当前页就加一个active样式类
if i == self.page_num:
tmp = '{1}'.format(self.url_prefix, i)
else:
tmp = '{1}'.format( self.url_prefix, i)
html_str_list.append(tmp)
# 加一个下一页的按钮
# 判断,如果是最后一页,就没有下一页
if self.page_num >= self.total_page:
html_str_list.append('>>')
else:
html_str_list.append('>>'.format( self.url_prefix, self.page_num+1))
# 加最后一页
html_str_list.append('尾页'.format( self.url_prefix, self.total_page))
page_html = "".join(html_str_list)
return page_html
# from utils.mypage import Page
# page_obj = Page(page_num, total_count, per_page=10, url_prefix="/books/", max_page=9,)
# ret = models.Book.objects.all()[page_obj.start:page_obj.end]
# page_html = page_obj.page_html()
# return render(request, "books.html", {"books": ret, "page_html": page_html})
# ====================================================================
# cookies 和session 因为http请求是无状态的,请求之间无关系
# cookie 保存在浏览器上的键值对,访问时会自动添加
# 例如:登录,输入密码登陆后,若成功,响应请求,让浏览器保存cookie本机,下次访问会默认带上cookie
# 都是键值对name value
"""
用法:得到响应对象 rep = render()或redirect或httpresponse
1,rep.set_cookies("xxx","yyy") 默认关闭浏览器失效
2,rep.set_signed_cookie("xxx","yyy",salt="zzz",max_age=10 单位是s) 设置加盐cookies
1,request.COOKIES['xxx'] 获取到
2,rep.get_signed_cookie("xxx",default="yy"取不到异常,加default,salt="zzz")
清除cookies:rep.delete_cookie("xxxx")
当多个页面需要校验cookies时
使用装饰器
def cookies(fun):
@wraps(fun) 修复注释,文档名等
def inner(request,*args,**kwargs):
if not request.get_singed_cookies.get("xxx",default="yyy",salt=""):
return render()
else:
跳转登录, 跳转后应该再次到请求的页面,不能固定,写死
1,获取请求的url:Request.path_info
redirect("..html/?next={}".format(url)) 在对应方法中取出next值,动态跳转即可
ret = fun(request,*args,**kwargs)
return ret
return inner
request.get_full_path:全路径带参数
request.path_info:不带参数
HTML中 action={{request.get_full_path}} 跳转到url中的路径 action 为空的时候默认跳转到当前url
action 要么不写要么 使用{{}}
expire= 针对ie的超时参数
path="/" 生效路径 默认是"/"
domain= 生效域名
source=False https传输
httponly=False 只能使用http协议传输,无法被javascript获取,不是绝对的,抓包可以修改
最大4kb
"""
# =============================================
# session 它依赖于cookie
# cookies 键值保存在客户端
# session中的键值保存在服务器,通过sessionid连接,保存在cookie中
# Django session 存
# 1,生成字符串
# 2,生成大字典对应1中字符串
# 生成的数据是在数据库中的 django_session session_key session_date(加密过得) expire_date session默认两周
# 3,返回给cookie 浏览器
# 取
# 1,从cookie中找到字符串
# 2,找到的大字典
# 3,大字典取值
""""
request.session['k1']
request.session.get('k1',None)
request.session.set('k1',"123") 存在则不设置
del request.session['k1']
request.session.delete() 删除所有session中的值,没神魔用,会使cookiezhaobudao对应值,等于无效
request.session.flush() session,cookie都删除
request.session.clear_expired() 数据库中的session记录不会自动删除,本语句就是删除过期的session
request.session.exists("key") 判断key存在
request.session.set_expiry(整数秒,datatime或timedelta,0表示关闭失效,None settings中设置) 失效的是cookie
"""
# settings中配置全局session信息
# 默认引擎
SESSION_ENGINE="django.contrib.session.backends.db"
# 缓存session
SESSION_ENGINE = "django.contrib.session.backends.cache"
SESSION_CACHE_ALLAS="default" # 使用的缓存别名默认内存缓存,也可memcache
# 文件Session
SESSION_ENGINE = "django.contrib.session.backends.file"
SESSION_FILE_PATH=None # 若为None tempfile.gettempdir获取临时地址
# 缓存加数据库
SESSION_ENGINE="django.contrib.session.backends.cached_db"
# 加密Cookie Session 加密的cookies 相当于没有使用session
SESSION_ENGINE="django.contrib.session.backends.singed_cookies"
# 其他设置
SESSION_COOKIE="sessionid"
SESSION_COOKIE_PATH="/"
SESSION_COOKIE_DOMAIN=None
SESSION_COOKIE_SECURE=False
SESSION_COOKIE_HTTPONLY=True
SESSION_COOKIE_AGE=1209600 # 2 WEEK
SESSION_EXPIRE_AT_BROWSER_CLOSE=False # 浏览器关闭清除Session
SESSION_SAVE_EVERY_REQUEST=False #每次请求后更改SESSION
# ==========================================
# cvb(类中get) 使用装饰器
# get,post (self,request) 装饰器中第一个参数是request,不匹配
# 解决方案:form django.utils.decorators import method_decorator
# get或post方法上 @method_decorator(自定义的装饰器) 也可以加在类上 但要指明方法
# @method_decorator(自定义的装饰器,name="get")
# 注意:其实在cvb中有dispatch方法
"""
def dispatch(self,request,*args,**kwargs): 用来选择是get请求还是post请求
return super(本类名,self).dispatch(request,*args,**kwargs)
若在此上边加,表示get,post都加装饰器
"""
# 补充 csfr token
# 对于cvb中
"""
from django.views.decorator.csrf import csrf_protect,csrf_exempt
@method_decorator(csfr_protect) 即时sttting中注释了,不验证跨站请求,加了本装饰器,也会验证
@method_decorator(csfr_exempt) 即时sttting中验证跨站请求,加了本装饰器,也不会验证,即取消跨站验证
只能放在cvb的dispatch方法上
"""
```
8_Django 中的html javascript
```
# json (javascript object Notation)
# 是javascript中的对象类型
# javascript 数字,字符串,布尔,数组,对象,null
# python 整形浮点,字符串,布尔,列表,字典,None 因此python不能json对象
# 二者通过json字符串转化
# json注意事项: 1,key必须双引号,
# 2,不能16进制,
# 3,不能undefined,
# 4,value不能是函数,或日起对象
# ====================================================
# JQuery 发ajax请求
"""
$.ajax(
{
url:"xxx",
type:"get"
data:{字典}
success:function(data){
}
}
)
ajax 发送跨站请求时
方法1:要把{{csrf_token}} 的值取到拼接到发送的数据中
方法2:引入jquery.cookie.js
type下多个headers:{"X-CSFRToken":$.cookie("csfrtoken")},
方法3:存入js文件,发ajax前引入,发送步骤与普通相同,不用再额外添加
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function (xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
"""
# ==============================================
# 对象的序列化 需要转为字典 然后变为json字符串,
# from django.core import serializers
# s= serializers.serializer("json",数据库查询的对象列表)
# ========================================
# sweetalert 插件,漂亮的弹出框
"""
1,swal("title","content","css")
css:success,warning,info,error
2,
swal({
title: "你确定要删除吗?",
text: "一旦删除就找不回来了",
type: "warning",
showCancelButton: true,
confirmButtonClass: "btn-warning",
confirmButtonText: "确认",
cancelButtonText: "取消",
closeOnConfirm: false,
showLoaderOnConfirm: true //若删除耗时,显示加载状态
},
function(){
// 向后端发送删除的请求
$.ajax({
url: "/delete/",
type: "post",
datatype:"json", //返回值的格式,回调函数中,按照此类型解析,不写就是字符串类型
traditional:True,// 为true,阻止深度序列化,不懂什么意思,反正就可以传list了
data: {"id":delId,"list":[1,2,3]}, 接受的时候使用getlist接受,但不能是双层列表
success:function (arg) {
swal(arg, "你可以跑路了!", "success");
$trEle.remove();
}
});
}
);
"""
# ==================================================
# Django 的form组件
# 第一步:定义class
# from django import forms
# from django.forms import widgets
# class RegForm(forms.Form):
# name = forms.CharField(max_length=16,label="用户名") 校验规则
# pwd = forms.CharField(
# label="密码",
# widget = widgets.PasswordInput(attr={'class':'xx'},render_value=True), //表示为密码类型,切验证后密码还存在 html相关
# min_length=6,
# error_message={"required":"不能为空","invalid":"格式错误","min_length":"最短6位"}
# )
# def fun(request):
# form_obj = RegForm()
# if reauest.method=="post":
# form_obj=RegForm(request.POST)
# if form_obj.is_valid :存入数据库
# name = form_obj.cleanned_data.get("name") 经过验证的数据
# 先从字典中去掉无用字符串pop("xxx")这种不报错
# .create(**form_obj.cleanned_data) 但要注意名字与数据库中列相同
# return render(request,"xxx.html",{"html":form_obj})
# 第二部,html中调用属性
#
# 或在form中自己写
"""
{{form_obj.name.label}}
{{form_obj.name}}
{{form_obj.name.errors.0}}
这种,只不过每个都要自己写
服务器端校验,通常是request中获取值,再返回,比较麻烦
django 校验后还可以保留信息
其他组件
单选按钮:forms.fields.ChoiceField(
choices=((1,"男"),(2,"女")),
label="性别",
initial=3,默认是3选中
widget = forms.widgets.RadioSelect
)
单选框,修改为widget = forms.widgets.Select 就是下拉菜单
多选框forms.MutipleChoiceField
initial=[1,3]
widget = forms.widgets.SelectMultiple 下拉菜单全部显示的那种
单选框,记住密码那种:forms.fields.ChoiceField
widget = forms.widgets.CheckboxInput
initial="checked"
多选框,
forms.fields.MultipleChoiceField(
choices=((1,"男"),(2,"女")),
label="爱好",
initial=[1,3],默认是3选中
widget = forms.widgets.CheckBoxSelectMultiple
)
"""
"""
自定义校验规则
from django.core.validators import RegexValidator
Charfield(
加上字段validators=[ 正则列表
RegexValidator(r"[0-9]+$","请输入数字"),
RegexValidator(r"^1[3-9][0-9]{9}$","159开头"),
]
)
在类中定义方法
def clean_name(self): 名字固定 clean_列名
value = self.cleanned_data.get("校验的列名 如name")
if "非法字符" in value:
raise ValidationError("含有非法字符")
return value
def clean(self): 重写父类clean方法,父类的方法默认什么都没干
pwd = self.cleaned_date.get("pwd")
...
if xx==yy
self.add_error("字段",ValidatorError("不一致") ) 应该在那里显示呢?
raise ValidatorError("不一致")
return self.cleaned_data
reg_pwd {{ form_obj.errors}}
"""
# =====================多选框从数据库取值
forms.CharField(
choices=models.xxx.objects.all().value_list("id",....)
#此时虽然可以获取,但是静态字段,若数据库增加,不重启服务器,新的数据不能获取
)
需要从写from的__init__方法
def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
self.fields['那一列'].widget.choices=models......
内置字段:等待添加....
```
9_ 中间件
======
```
# importlib的使用
import importlib
o = importlib.import_module("模块字符串")
# 这样即可导入模块 ,其实是通过反射
# 要实现权限验证,如登陆后访问,原来是装饰器,但若函数过多...
# 中间件:官方说是 用来处理Django的请求和响应的框架级级别的钩子,轻量级
# 全局的,慎用,使用不当,影响性能 说白了就是在执行urls.py前后,执行某些方法
# setting MIDDLEWARE 定义后加入列表即可
# 固定方法 其实中间件相当于过滤器
from django.utils.deprecation import MiddlewareMixin
class A(MiddlewareMixin):
# 先request,次view 最后response
def process_request(self,request):pass
# 按照setting中的顺序,请求时 123 响应是 321 是反向
# 返回None 继续执行url,若有return httpresponse 则直接返回
def process_request(self,request,response):# 必须要两个参数,且必须返回值,要么自定义返回 ,或返回视图的response
pass
def process_view(self,request,view_func,view_args,view_kwargs):
"""
:param request: 请求
:param view_func: 要执行的函数名字
:param view_args: 位置参数
:param view_kwargs: 关键字参数
:return:
在找到urls.py前执行,按顺序执行,
"""
def process_exception(self):pass
# 只有在视图函数中出现异常的时候执行, 也是倒序
# 返回None,继续执行其他中间件的exception
# HttpResponse,跳过其他中间件的exception ,通常是视图页面错误,既不能正常返回,在此定义返回页面
def process_template_response(self,request,response):pass
# 倒序执行, 在视图函数执行完毕 但没有返回render()之前
# 返回Noneh或HttpResponse
# 因此返回的对象中必须存在render()方法,然后会执行render()方法,名字必须为render(),内容可自定义
# request列表没执行完毕,某一个request返回了响应,则直接跳到该中间件的response
# request列表执行完毕,会继续第一个中间件的view --->到最后一个view
# 若view列表没执行完毕,某一个返回响应了,后边的view不执行, 跳到第一个response(返回时候的第一个res) (urls中的view不执行)
# 若view列表执行完毕,执行urls view ,然后response列表
#
# 1,process_request
# urls.py
# 2,process_view
# view
# 3,有异常process_exception
# 4,若视图函数返回对象有render()方法,执行
# 5,process_response
#
# day74
# 2018 - 05 - 21
#
# 课程安排
# 周一:
# 中间件
# auth模块 + 分析BBS项目需求(小组讨论把表结构设计出来)
#
#
# 1.
# 今日内容
# 中间件:http: // www.cnblogs.com / liwenzhou / p / 8761803.
# html
#
# 1.
# URL的白名单
# url = ["/xx/", "/oo/", "/haha/"]
# 2.
# 登陆之后才能访问某些URL
# 之前使用装饰器
#
# 中间件的定义:
# wsgi之后
# urls.py之前
# 在全局
# 操作Django请求和响应的模块!
#
# 中间件的使用:
# 5
# 个固定的方法
# process_request(self, request)
# 执行顺序:
# 按照注册的顺序(在settings.py里面设置中
# 从上到下的顺序)
# 何时执行:
# 请求从wsgi拿到之后
# 返回值:
# 返回None,继续执行后续的中间件的process_request方法
# 返回response, 不执行后续的中间件的process_request方法
#
# process_response
# 执行顺序:
# 按照注册顺序的倒序(在settings.py里面设置中
# 从下到上的顺序)
# 何时执行:
# 请求有响应的时候
# 返回值:
# 必须返回一个response对象
#
# process_view(self, request, view_func, view_args, view_kwargs):
# 执行顺序:
# 按照注册的顺序(在settings.py里面设置中
# 从上到下的顺序)
# 何时执行:
# 在urls.py中找到对应关系之后
# 在执行真正的视图函数之前
# 返回值:
# 返回None,继续执行后续的中间件的process_view方法
# 返回response,
#
# process_exception(self, request, exception)
# 执行顺序:
# 按照注册顺序的倒序(在settings.py里面设置中
# 从下到上的顺序)
# 何时执行:
# 视图函数中抛出异常的时候才执行
# 返回值:
# 返回None, 继续执行后续中间件的process_exception
# 返回response,
#
#
#
# process_template_response(self, request, response)
# 执行顺序:
# 按照注册顺序的倒序(在settings.py里面设置中
# 从下到上的顺序)
# 何时执行:
# 视图函数执行完,在执行视图函数返回的响应对象的render方法之前
# 返回值:
# 返回None, 继续执行后续中间件的process_exception
# 返回response,
#
#
# Django调用
# 注册的中间件里面五个方法的顺序:
# 1.
# process_request
# urls.py
# 2.
# process_view
# view
# 3.
# 有异常就执行
# process_exception
# 4.
# 如果视图函数返回的响应对象有render方法, 就执行process_template_response
# 5.
# process_response
#
# Django已经学过的知识点:
# 1.
# Urls.py
# 路由系统:
#
# 正则
# 分组匹配 --> 位置参数
# 分组命名匹配 --> 关键字参数
#
# 分级路由
# include
#
# 给路由起别名
# name = "xx"
#
# 反向解析url
# view
# from django.urls import reverse
#
# reverse("xx", args=[1, 2, 3])
# reverse("xx", kwargs={”k
# ": "
# v
# "})
#
# 自取其辱
#
# 2.
# 视图
# views.py
# request
# request.method
# request.GET --> URL里面的参数
# request.POST --> post请求的数据
#
# request.path_info --> 路径
# request.get_full_path() --> 路径加路径的参数
#
# response
# 新手必备3件套
# render(request, "xx.html", {“k”: "v", ...})
# HttpResponse("响应")
# redirect("/index/")
# redirect("http://www.luffycity.com")
#
# from django.http import JsonResponse
#
# JsonResponse()
#
# FBV和CBV
#
# 函数装饰器和方法装饰器的区别
#
# 3.
# 模板
#
# filter
# 内置的filter方法
# 自定义的filter方法
#
# tag
# 内置的tag
# 自定义的simpleTag
# 自定义的inclusionTag
#
# 母版和继承
#
# { % extends ‘base.html’ %}
#
# { % block
# page - main %}
# { % block
# small %}
# { % endblock
# small %}
# { % endblock
# page - main %}
#
#
# 组件
# { % include
# nav %}
#
#
# 静态文件相关的tag
#
# 在模板语言里面反向解析url
#
# { % url
# 'url的别名'
# xx %}
#
#
# 4.
# ORM
#
# 对应关系
# 类 --> 数据表
# 对象 --> 数据行
# 属性 --> 字段
#
# Django连接MySQL数据库的步骤:
# 1.
# 手动创建库
# 2.
# 配置settings.py中数据库的连接信息
# 3.
# 修改settings.py同目录下的__init__.py文件,添加两句
# import pymysql
#
# pymysql.install_as_MySQLdb()
# 4.
# 在app下面的models.py中定义类,类一定要继承mdoels.Model
# 5.
# 执行两句命令
# 1.
# python
# manage.py
# makemigrations
# 2.
# python
# manage.py
# migrate
#
# 操作数据表
#
# 操作数据行(增删改查)
# 单表
# 外键
# 多对多
# 一对一
#
# ORM高级:
# 常用字段和方法
# 必知必会13条
# 神奇的双下划线
# 跨表的正向查询反向查询
#
# F和Q
#
# 聚合和分组
#
# 事务
#
# 执行原生的SQL语句
#
# 5.
# Cookie和Session, 分页
#
# 6.
# AJAX
#
# $.ajax({
# url: “”,
# type: "post",
# data: {"k1": JSON.stringify([1, 2, 3])},
# success: function(data)
# {
#
# }
# })
# 7.
# form表单
#
# 8.
# 中间件
```
10_auth模块
=========
```
# 当在html要获取当前用户信息的时候,通常是session存id
# 视图中查询到,传入html,存在问题:需要的页面都要获取,再传入
# 解决方案:自带的中间件,自带的倒数第三个 auth有关的
"""
python manage.py createsuperuser 向auth_user 添加用户
from django.contrib import auth
obj = auth.authenticate(username="xx",password="xx")
将认证的用户放入request.user:
auth.login(request,obj)根据cookie,将用户放入session, 检测当前用户,下次来的是会有请求中会放入user
auth.lgout(request) 相当于request.session.flush()
from django.contrib.auth.decorators import login_required
需要登陆权限的视图 @login_requried() 装饰器 默认""
默认LOGIN_URL="/accounts/login/" 不存在 添加 修改即可 而且实现的登陆跳转
request.user.is_authenticated() 返回
from django.contrib.auth.models import User
注意username不能重复
User.Objects.create(...) 不能使用这个创建,创建后是明文密码
User.Objects.create_superuser()
User.Objects.create_user(....) 密文密码
obj.check_password("密码") 检测密码正确与否
obj.set_password("xxx") 修改密码
obj.save() 修改后要保存
"""
# ====================================
# 扩展自带的表
# 1,models.OneToOneField(to=User)
# 2,继承自带的类,auth_user 不会创建了
"""
from django.contrib.auth.models import User,AbstractUser
继承后添加额外属性
若使用本方法 sttings指定 AUTH_USER_MODELS='appname.类名'
"""
python manager.py createsuperuser
```