Administrator
发布于 2026-05-17 / 1 阅读
0

python-Django

--- title: Django --- 1,http ====== 小提示:"{:0\>3}".formate(9) 右对齐若小于3位 ---\>00n 0位占位符,\> 表示右对齐 响应格式 ---- 请求格式 ---- ``` import socket import os # ========================================================= def ret(path): dir = "../html/" file = os.path.join(dir,path.strip(r"[/\]")) if os.path.exists(file): with open(file,"rb") as f: return f.read() else: with open(os.path.join(dir,"error.html"),"rb") as f: return f.read() # ========================================================= sk = socket.socket() sk.bind(("127.0.0.1",8080)) sk.listen() while True: conn,_ = sk.accept() data = conn.recv(8096) data_str = str(data,encoding="utf8") list = data_str.split("\r\n") # for i in list: # print(i) # 获取每行,还可以通过 空格分隔 获取访问路径,根据路径返回不同那内容 # # 通过请求路径,建立字典,对应但会数据,可直接返回 firstLine = str(list[0]).split(' ') temp = firstLine[1].split("?") path = temp[0] #print(path) conn.send(b'http1.1 200 \r\n\r\n') conn.send(ret(path)) conn.close() sk.close() """ # http 请求 GET /sadasd/?name=dzf HTTP/1.1\r\n Host: 127.0.0.1:8080\r\n Connection: keep-alive\r\n Upgrade-Insecure-Requests: 1\r\n User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36\r\n Sec-Fetch-Mode: navigate\r\n Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3\r\n Sec-Fetch-Site: none\r\n Accept-Encoding: gzip, deflate, br\r\n Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7\r\n\r\n' """ # ========================================================= """ Python中 Web框架的分类: 1. web框架的本质: socket服务端 与 浏览器的通信 2. socket服务端功能划分: a. 负责与浏览器收发消息(socket通信) --> wsgiref/uWsgi/gunicorn... 自己写的长时间连接会报错 b. 根据用户访问不同的路径执行不同的函数 c. 从HTML读取出内容,并且完成字符串的替换(动态网站的本质) --> jinja2(模板语言) 1. 按上面三个功能划分: 1. 框架自带a,b,c --> Tornado 2. 框架自带b和c(和jinja2类似),使用第三方的a(wsgiref) --> Django 3. 框架自带b,使用第三方的a和c(jinja2) --> Flask 2. 按另一个维度来划分: 1. Django --> 大而全(你做一个网站能用到的它都有) 2. 其他 --> Flask 轻量级 """ # 安装jinja2 from wsgiref.simple_server import make_server # a 功能 from jinja2 import Template # c功能 ​ ​ def index(): with open("09 jinja2版web框架.html", "r", encoding="utf-8") as f: data = f.read() template = Template(data) # 生成模板文件 # 从数据库中取数据 import pymysql conn = pymysql.connect( host="127.0.0.1", port=3306, user="root", password="123456", database="day59", charset="utf8", ) cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) cursor.execute("select * from userinfo;") user_list = cursor.fetchall() # 实现字符串的替换 ret = template.render({"user_list": user_list}) # 把数据填充到模板里面 return [bytes(ret, encoding="utf8"), ] def home(): with open("home.html", "rb") as f: data = f.read() return [data, ] # 定义一个url和函数的对应关系 URL_LIST = [ ("/index/", index), ("/home/", home), ] def run_server(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ]) # 设置HTTP响应的状态码和头信息 url = environ['PATH_INFO'] # 取到用户输入的url func = None # 将要执行的函数 for i in URL_LIST: if i[0] == url: func = i[1] # 去之前定义好的url列表里找url应该执行的函数 break if func: # 如果能找到要执行的函数 return func() # 返回函数的执行结果 else: return [bytes("404没有该页面", encoding="utf8"), ] ​ if __name__ == '__main__': httpd = make_server('127.0.0.1', 8000, run_server) print("Serving HTTP on port 8000...") httpd.serve_forever() """ Title ​ ​ {% for user in user_list %} {% endfor %}
ID 用户名 密码
{{user.id}} {{user.name}} {{user.pwd}}
""" ``` 2 django基础 ---------- ``` # ============================================================================== # 安装 pip install Django==2.2.4 # setting 中添加库 https://pypi.tuna.tsinghua.edu.cn/simple/ 防止time out # cmd 新建项目 进入目标目录 django-admin startprojext project_name # 或pycharm 新建Django 使用存在的解释器,第二个 # # 项目配置 """ 1,urls.py urlpatterns:保存了路径与函数的对应关系 在该文件中定义新的项,并写函数,支持正则 也可以建立专门的函数文件,只需在urls 中导入即可 import django.shortcuts import HttpResponse def admin(request): # request为所有请求的参数 return HttpResponse("xxx) patterns,函数内容都可以动态修改, 项目启动 普通启动后,只能127.0.0.1 访问 若要使用ip访问,allowed_host = ['*'] runserver 0.0.0.0:80 1,cmd中python manage.py runserver [port] 2,选择项目 ,点击旁边三角 edit config 也可改端口 template下建立html文件 所有与html文件有关的设置都放在 setting的templates下 如何那绝对路径:在/下建立文件 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 指定html文件目录:'DIRS': [os.path.join(BASE_DIR, 'templates')] 用到的时候 直接写文件名即可,"./写template",或"./xx/xx.html" 不能直接写文件名 返回方式: 字符:直接写或文件--->字符 打开文件 字节返回 文件使用模块: render(request,"文件路径") return render(request,"Hello.html") # 此处可直接写文件名 此处注意,若在template下有多级文件夹,文件夹下有文件,此时访问 只写(xxx/xx.html) 不用加"/",以文件夹开头即可 ​ 对于static下的文件 ​ 2,配置静态文件,js,css等 setting 最后添加 STATICFILES_DIRS=[ os.path.join(BASE_DIR,"static") # static 为自己制定的文件夹,名字随意,可配置多个 ] STATIC_URL="/static/" 就代表的是 "D:/xxx/yy/static/" 别名 若有多个都当做在static下 html引用时使用绝对路径就不用从头开始写 例:href="/static/bootstrap/css/bootstrap.min.css" 3,若出现403 中间价问题 注释settings中47行 'django.middleware.csrf.CsrfViewMiddleware', 4,连接数据库,后边详细 """ # 登录时,一个函数处理即可,若为get 表示请求html,若为post,处理数据,返回页面 # if request.method=="POST" "GET" # 默认的页面请求是get,a标签也是get ​ """ def if post: 处理 return html render(request,"xx.html",{"msg":"xxx"}) html中使用{{msg}}可获取 ​ redirect 模块 跳转 return redirect("http://www.baidu.com") # 让浏览器请求新的页面,不是服务器返回的 return redirect("/login/") # 本网站 用"/"包裹 ​ """ # =============================================== # app:方便在项目中管理实现不同的业务功能 """ project -->项目 (学校) app --> 学院(软件学院,量子力学) 1,创建app 在cmd ,某个project 根目录 python(3) manage.py startapp app_name 执行后会在根目录下创建文件夹 app_name 文件夹 migrations 文件 __init__.py admin.py:管理控制台 apps.py:app相关的配置 models.py:ORM的类 entity tests.py:测试文件 views.py:函数文件 2,或在创建项目的时候直接添加一个 settings INSTALLED_APPS 配置,添加上"app_01" 或"app_01.apps.App_01Config" 类 推荐 """ # ============================================= # ORM 简单,开发效率高, 执行效率低 # 不能创建数据库 # 步骤 """ 1,创建数据库 2,setting 配置数据库 DATABASES = { 'default': { #数据库类型 'ENGINE': 'django.db.backends.mysql', 'HOST':'127.0.0.1', 'PORT':3306, 'NAME':'test', 'USER':'root', 'PASSWORD':'xxxx' } } 3,告诉Django用什么连接数据库??MYsqlDB(不支持python3), pymysql mysqldb是默认的,需要更改为pymysql 项目下,__init__.py 不是app的init import pymysql pymysql.install_as_MySQLdb() 4,创建类 modules.py 必须在个文件,必须继承(models.Model) class UserInfo(models.Model): id = models.AutoField(primary_key=True) # 创建一个自增的主键字段 name = models.CharField(null=False, max_length=32,unique=True) # 创建一个varchar(20)类型的不能为空的字段 5,创建表 创建后 不能修改,若要修改只能通过 modules修改,不然函数调用会报错 1. python3 manage.py makemigrations # 记录moduls 的变化,会记录在app/migrations下 2. python3 manage.py migrate # 转变为sql执行 可能pymsql驱动的mysqlclient客户端版本过低,修改G:\Program\Python\Python3.7.4\Lib\site-packages\django\db\backends\mysql\base.py 注释掉如下,但还有错误 str 编码错误,还要修改operations.py # if version < (1, 3, 13): # raise ImproperlyConfigured('mysqlclient 1.3.13 or newer is required; you have %s.' % Database.__version__) # 需要更换pymsql 或 下载mysqlclient,手动下载安装 https://www.lfd.uci.edu/~gohlke/pythonlibs/#mysqlclient mysqlclient‑1.4.4‑cp37‑cp37m‑win32.whl 37为对应版本,还有显卡版本 注意app一定要在setting注册 否则会失败 # init 中不用写了 6, 会创建很多表,默认实体表名为 app_name_class_name 还有其他权限表,会话表等 """ # ======================================================== """ request.GET[POST] 大字典 在函数中获取数据库中数据 from app_01 import modules ### 查询所有的数据 ret = modules.Userinfo(类名).objects.all().order_by('id') 列表返回 userinfo对象,并根据id排序 ret[0].id 或name 即可得到对应数据 使用render传入html即可 ### 创建 modules.Userinfo(类名).objects.create(name="xxx") ### 删除 request.Get.get("id",None) ret = modules.Userinfo(类名).objects.get(id="xxx") 请求不到会报错,可以使用 filter(id="xxx") ret.delete() ### 修改 request.Get.get("id",None) ret = modules.Userinfo(类名).objects.get(id="xxx") 请求不到会报错,可以使用 filter(id="xxx") ret.name = new_name ret.save() # 提交到数据库 """ ``` 3 django web实例 ============== ``` # 1,get 携带数据最大40k url长度不同浏览器不同2k-8k # 2,... makemigrate app_name 只有一个时可省 # 3,外键 """ class A(modules):pass class B(modules): public = modules.Foreignkey(to=A) # A必须在前面存在 public = modules.Foreignkey(to="A") # 没要求,只要最后有A即可 最后 public列在库中名为 public_A主键名,好像是这个如果不是的话就是 public_id,(好像这个可能比较大) 注:存入的时候public存的是A的id,使用create(public_id=xxx) 或使用 create(public=查到id的对象) 但获取get() B对象时 获取到所有属性,public 这个属性对应的是一个对象,若要获取某个属性,需再次加点 """ # 4,数据库中已存在数据,此时修改modules,例如添加列, # 会指定让你输入默认值,或直接在modules中 default="xxx" # 5,多对多关系,需要第三张表 (id,table_id,table2_id) """ # 例如作者,书 class book(modules):pass 只写 属性即可 class auther(modules): ..... book=modules.ManyToMany(to="book") auther 类执行后会生成2个表 第一张:app_name_auther,注意没有book属性 第二张:app_name_ManyToMany所在类名_赋值名(book) 属性:id ,auther_id,book(book类名)_id 例:查询某个作者 1,先ret = get(id=x)得到作者 2,ret.book(是上边的manytomany的book).all() 帮助查询关联的对象 控制台打印all 有括号 列表返回所有书对象 for 显示的时候 for b in ret.book.all 没有括号 """ # 6,request.POST.get("xxx") 若xxx中多个参数 返回值列表中对后一个 # 使用getlist("xxx") 获取列表 # 7,添加作者并关联存在的书本 # author =....creat(name=...等属性赋值) 注意没有book # author.book(manytomany那个book).set(getlist中得到的books列表) # 注意不用save() # 8,删除作者 普通的删除,只不过是关联删除,先删书,再删作者 # 9,更改作者,与普通更改相同,获取目标对象obj,修改普通属性, # 再obj.book.set(获取到的list) obj.save() ``` 4,MVC ===== ``` # 在python中称为MTV # module(modules), # view(Templates) # controller(urls,views), # 母板 """ 1,新建公共html .... {# 这里是页面不同部分 #} {% block page_main(名字随意) %} {% endblock %} .... 2,建立子html {% extends "base.html路径"%} {% block page-css %}{% endblock%} {% block page-main %}

直接写即可,不用body等标签

{% endblock%} {% block page-js %}{% endblock%} 用处:1,替换固定的模板内容 2,替换某个html专用css ,其实在子html中可直接加入cssdeng 但会造成css位置混乱,此方法可使css等都位于head标签 注意: 1,模板不能嵌套, 2,extends行一定在第一行, 路径必须加引号 3,可有多个block,一般3个 4,views中返回的是子html,不是base.html """ # 导入组件:就是替换 """ 将导航条放入单一功能模块 {% include "xxx.html" %} """ # 引入静态文件 """ 若static别名更改,引入的css等路径都要更改 解决方案: 路径拼接 {%load static%} 即可 """ # simpletag """ 复杂的filter 路径是实在app下templatags下 from... register... 注意register不能更改 @register.simple_tag(name="xx") 可不指定名字默认是函数名 def my_sum(arg1,arg2,arg3): return arg1+arg2+arg3 ​ html使用 {%load xxx文件%} {% xx arg1 arg2 arg3 %} """ # inclusion_tag 返回html代码 """ 与simple类似 @register.inclusion_tag("xxx.html") 注意此处没有name ,调用使用函数名,向下12行 def my_inclusion(arg1): data = 处理参数args,变为其他数据,列表,字典等 return {"result":data} xxx.html {% for i in result %} # 加入为迭代对象
  • {{i}}
  • {%endfor%}
    调用{{my_inclusion arg}} """ ​ # ====================================== # view(接受响应的部分) # CBV(基于类的视图) FBA(基于函数的视图:前面的都是) """ form django.views import View class add_list(View): # urls调用时使用类名add_list ,会根据请求方式转到对应方法 def get(self,request):pass def post(self,request):pass urls 中 path("xx",add_list.as_view()) 调用 """ # request """ request.method request.GET request.POST request.path_info "/xxx/yy/" 形式,不带ip,端口,参数 request.body 若为get ---->b'' 若为post ----->b'提交的参数名=值(若为中文会变成%E6879AS7D54%等编码数据)' """ # ============================================= # 上传文件 """ form 注意使用post 还有enctype="multipart/form-data" def upload(request): request.FILES 字典,{"file1":obj,"file2",obj} filname =request.FILES['表单中name'].name with open0..... for i in request.FILES['表单中name'].chunks() f.write(i) """ # =============================================== # response """" 1,HttpResponse 2,render 3,redirect ​ 4,返回json import json return HttpResponse(json.dumps(xxx)) 返回json字符串 或 from django.http import JsonHttpResponse # 封装的json ,不能串list return JsonHttpResponse(xxxx)直接返回 若要传list JsonHttpResponse(xxxx,safe=False) 即可 """ ``` 5,django 路由系统 ============= ``` # 路由系统 """ urlpatterns=[ url,path(2.0以后)(正则,函数名,参数,别名) ] r"^book/[0-9]{2,4}/$" r"^book/([0-9]{2,4})/([a-zA-Z]{2})/$" 分组匹配时,会把分组的内容当做参数传入:位置参数 例: book/11/ac 对应函数应该为(request,arg1,arg2) 接受 <(?P\w*)> 匹配"<里边是字符>" (?P=name1) 复制匹配规则 多路径匹配, 最后注意加 / $ 对于路径上的"/" 最后会默认添加"/" 若要取消 settings APPEND_SLASH=False ​ 分组命名匹配 r"^book/(?P[0-9]{2,4})/(?P[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中调用属性 #
    关闭浏览器校验 # {{csrf_token}} # {{form_obj.as_p}} 每个都用p标签包裹 # {{form_obj.errors.pwd}} #

    #
    # 或在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 ```