小提示:"{: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()
"""
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
</head>
<body>
<table border="1">
<thead>
<tr>
<th>ID</th>
<th>用户名</th>
<th>密码</th>
</tr>
</thead>
<tbody>
{% for user in user_list %}
<tr>
<td>{{user.id}}</td>
<td>{{user.name}}</td>
<td>{{user.pwd}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
"""
# ==============================================================================
# 安装 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() # 提交到数据库
"""
# 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()
# 在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 %}<h1>直接写即可,不用body等标签</h1>{% 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%}
<link href="{% static 'bootstrap/xxx'%}" rel="stylesheet>
或者
{%load static%} 也要导入
<link href="{%get_static_prefix%}bootstrap/xxx" rel="stylesheet>
多次使用的图片
{% load static%}
{%static 'xxx.jpg' as yy%}
<img src="{{yy}}"/> 即可
"""
# 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
<ui>
{% for i in result %} # 加入为迭代对象
<li>{{i}}</li>
{%endfor%}
</ui>
调用{{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) 即可
"""
# 路由系统
"""
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<name1>\w*)> 匹配"<里边是字符>" (?P=name1) 复制匹配规则
多路径匹配, 最后注意加 / $
对于路径上的"/" 最后会默认添加"/" 若要取消
settings APPEND_SLASH=False
分组命名匹配
r"^book/(?P<year>[0-9]{2,4})/(?P<month>[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()
# 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)
# 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中会变为 <input type="hidden" name="csrfmiddlewaretoken"
value="随机字符串"/>
若出现跨站请求即会禁止 一般就是403
在render中 生成html时,会自动产生key,通过Post接受参数时,会自动校验,不通过即拒绝
"""
# 分页
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('<li><a href="{}?page=1">首页</a></li>'.format( self.url_prefix))
# 判断一下 如果是第一页,就没有上一页
if self.page_num <= 1:
html_str_list.append('<li class="disabled"><a href="#"><span aria-hidden="true">«</span></a></li>'.format(self.page_num-1))
else:
# 加一个上一页的标签
html_str_list.append('<li><a href="{}?page={}"><span aria-hidden="true">«</span></a></li>'.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 = '<li class="active"><a href="{0}?page={1}">{1}</a></li>'.format(self.url_prefix, i)
else:
tmp = '<li><a href="{0}?page={1}">{1}</a></li>'.format( self.url_prefix, i)
html_str_list.append(tmp)
# 加一个下一页的按钮
# 判断,如果是最后一页,就没有下一页
if self.page_num >= self.total_page:
html_str_list.append('<li class="disabled"><a href="#"><span aria-hidden="true">»</span></a></li>')
else:
html_str_list.append('<li><a href="{}?page={}"><span aria-hidden="true">»</span></a></li>'.format( self.url_prefix, self.page_num+1))
# 加最后一页
html_str_list.append('<li><a href="{}?page={}">尾页</a></li>'.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 novalidate> 关闭浏览器校验
# {{csrf_token}}
# {{form_obj.as_p}} 每个都用p标签包裹
# {{form_obj.errors.pwd}}
# <p><input type="submit" /></p>
# </form>
# 或在form中自己写
"""<div>
{{form_obj.name.label}}
{{form_obj.name}}
<span>{{form_obj.name.errors.0}}</span>
</div>这种,只不过每个都要自己写
服务器端校验,通常是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......
内置字段:等待添加....
https://www.cnblogs.com/liwenzhou/
# 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.
# 中间件
# 当在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