django框架
Posted liqianxin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了django框架相关的知识,希望对你有一定的参考价值。
django框架
要回忆起一些HTTP的知识。
HTTP协议的四大特性:
1.基于请求响应
2.基于TCP/IP作用于应用层的协议
3.无状态
4.短链接
请求的格式:
1.请求首行:请求方式 url HTTP版本
2.请求体
3.空行
4.请求体
响应的格式:
1.响应首行:HTTP版本 状态码 状态码描述
2.响应头
3.空行
4.响应体
手撸基础版
我们通过socket制作一个服务器运行之后,将浏览器当做客户端进行链接。
- 输入ip:port就是发起链接请求,如(127.0.0.1:8000/index) 此时会按照请求格式发送一个请求。
- 服务端接受到请求之后,会按照响应的格式返回一个响应。
基于这样的思路,我们就可以自己写一个web框架。
首先自己先写一个web框架。
from socket import socket
# 创建一个服务器
server = socket()
server.bind((‘127.0.0.1‘, 8000))
server.listen(3)
while True:
conn, addr = server.accept()
# 当浏览器作为客户端连接时,会发送请求,此时的data就是发送的请求
data = conn.recv(1024)
# 按照空格进行切割,会得到一个被拆分的请求体,而url请求按照请求格式位于下标1处。
url = data.split()[1].decode(‘gbk‘)
conn.send(b‘HTTP/1.1 200 OK
‘) # 发送一个响应格式的前三个部分。
if url == ‘/index‘:
conn.send(b‘index‘) # 发送的是响应体
print(123)
else:
conn.send(b‘nothing‘) # url不存在则会发送nothing。
conn.close()
当前的手撸版本是有问题的,需要所有人都要写,代码重复;对于请求也只能拿到一个url请求;且无法解决并发的问题。
手撸web框架加强版(wsgiref)
为此,引入了一个对请求可以进行解析封装的模块,在响应的时候也可以封装成HTTP协议的模块:wsgiref模块。
# 首先介绍一下wsgiref模块的用法
from wsgiref.simple_server import make_server # 导入模块
run(env, response) # run函数需要自定义,但是务必有这两个参数。
env: 是请求相关数据。
response:是响应的相关数据
return:返回浏览器的数据
make_server(ip,port,run) # 监听ip:port地址,一旦有请求交给run函数。
路由就是输入的ip:port的后缀。如:127.0.0.1:8000/index,其中/index就是路由。
from wsgiref.simple_server import make_server
def run(env, response):
response(‘200 OK‘, []) # 这一句是必须有的。
url = env.get(‘PATH_INFO‘) # 路由在env这个大字典中的key是PATH_INFO
return [b‘I dont know‘]
if __name__ == ‘__main__‘:
server = make_server(‘127.0.0.1‘, 8080, run)
server.serve_forever() # 处理一个请求,直到处理完毕。
这时,如果要设置多个路由的时候,就可以把他们分成不同的区域。
1. wsgiref层:运行服务端,处理请求。
2. urls.py:内部存放路由和视图函数的对应关系。
3. views.py:存放视图函数。
wsgiref的代码
from wsgiref.simple_server import make_server
import urls
import views
def run(env, response):
response(‘200 OK‘, []) # 这一句是必须有的。
path_info = env.get(‘PATH_INFO‘) # 路由在env这个大字典中的key是PATH_INFO
func = None
# 查看path_info是否已经在urls.py中定义,定义的话就将视图函数的内存地址赋给func
for url in urls.urls:
if path_info == url[0]:
func = url[1]
break
# 如果未定义,则抛出404错误
if not func:
return [b‘404‘]
# 定义之后就执行,返回数据
res = func(env)
return [res.encode(‘gbk‘)]
if __name__ == ‘__main__‘:
server = make_server(‘127.0.0.1‘, 8080, run)
server.serve_forever()
# urls.py的代码
import views
urls = [
(‘/index‘, views.index)
]
# views.py的代码
def index(env):
return ‘/index‘
上述代码只写了一个对应关系,如果之后想再次添加多的url,只需要在urls.py添加对应函数关系,然后在views.py中添加对应的函数关系就可以了。
手撸框架终极版(jinja2)
不过这样只是显示出来一个简单的一句话,我们当然不满足于此,想要返回一个html页面,这个时候就需要我们先定义一个文件夹templates,专门用来存放html文件了。
首先了解一下网页的分类:
- 静态网页:跟后端数据没有交互,数据一层不变。
- 动态网页:跟后端交互数据,数据实时获取的。
获取的数据是在数据库中的,我们可以通过pymysql模块进行连接数据库获得数据,然后通过jinja2模块将数据传递给html。该模块需要安装。pip install jinja2
首先介绍一下jinja2模块,它是一个模板,主要就是通过后端发送的数据替换html文件的一些变量控制html的显示。
def get_dict(env):
‘‘‘将数据库中的数据传给前端页面‘‘‘
from jinja2 import Template
from models import get_data
user_data = get_data() # 拿到了数据库中的数据
with open(r‘templates/get_dict.html‘,‘r‘,encoding=‘utf-8‘) as f:
data = f.read()
tmp = Template(data)
res = tmp.render(userdata=user_data) # 把user_data传递给了html
return res
在models.py中写入
def get_data():
‘‘‘从数据库中拿到数据‘‘‘
import pymysql
conn = pymysql.connect(
host=‘127.0.0.1‘,
port=3306,
user=‘root‘,
passwd=‘123456‘,
db=‘login‘,
autocommit=True,
)
cur = conn.cursor(pymysql.cursors.DictCursor)
sql = ‘select * from userinfo‘
cur.execute(sql)
data = cur.fetchall()
return data
模板语法
‘‘‘当模板语法在后端将变量数据传递给html文件后,就能在html中通过实用一些模板语法来达到替换数据的效果。‘‘‘
针对变量的话,模板语法使用的是{{ 变量 }},其内部可以使用点的方式,也可以使用[属性]的方式。类似于python语句。
{{ user }}
{{ user.get(‘username‘)}}
{{ user.age }}
{{ user[‘hobby‘] }}
针对控制语句的话会使用{% 逻辑 %}
{% for i in l %}
{% end for %}
{% if 条件 %}
{% elif 条件%}
{% else %}
{% end if %}
手撸代码完毕,这就是一个简单的框架,可以把流程图画出来。跟django的生命周期流程图极为相似。
django的基本操作
首先需要安装django框架,推荐使用1.X版本。是一个专门用来开发app的web框架,每一个app就是一个独立的功能模块。
# 创建django项目的方式有两种:
# 第一种:通过命令行创建。后两个命令都是在django项目内实现的。
django-admin startproject 项目名 # 创建项目
python manage.py startapp app名 # 创建app项目
python manage.py runserver # 运行项目
‘‘‘
通过命令行的方式创建的项目有一些配置问题需要自己解决,首先创建完项目需要手动创建一个templates文件夹,然后在settings内的TEMPLATES中DIRS添加templates的路径。
在创建完app的时候,务必要在INSTALLED_APPS中注册app。
‘‘‘
# 第二种:通过pycharm创建项目
在创建一个django项目之后,所有的配置都不需要担心,完美的被pycharm帮你解决了,还可以附送一个注册过的app,但是之后自己注册的app同样需要再次注册。
django中的主要文件介绍
‘‘‘
-mysite 项目文件名
--mysite 主要的框架文件夹
---settings 配置文件
---urls.py 路由与试图函数的对应关系
---wsgi.py wsgiref模块,暂不考虑
--manage.py django的入口文件
--db.sqlite3 django自带的数据库
--app01 应用
---admin.py django后台管理
---apps.py 注册使用
---migrations 文件夹,数据库迁移记录
---models.py 数据库相关的模型类
---tests.py 测试文件
---views.py 视图函数
‘‘‘
django框架小白必回三板斧
HttpResponse(‘字符串类型数据‘) 返回字符串类型的数据
render(request, url) 返回html文件
redirect(url) 重定向
静态文件配置
templates文件夹内部放的都是html文件,而所有的静态文件大都放在static文件夹下,我们在创建一个static文件夹。
static文件夹:内部存放的是静态文件,能直接调用使用的文件,如网站写好的js文件,css文件,图片文件等等。
在创建完static文件之后,我们就需要在settings的内部进行配置,在最末尾能够看到一个STATIC_URL = ‘/static/‘
这个相当于令牌一样的东东,拿着这个令牌才能准许进入,想要访问静态文件,必须‘/static/’开头。我们需要在添加一个static的路径。
STATICFILES_DIRS = [
os.path.join(BASE_DIR, ‘static‘)
]
当我们在html的表头中想要使用静态文件中的文件的话,有两种方式:
# 第一种
{% load static %}
<link rel=‘stylesheet‘ href=‘{% static ‘路径‘ %}‘>
# 第二种是直接写全路径。
request对象方法初识
‘‘‘
在视图函数中的request参数是一个含有请求的请求对象,内部封装了很多方法,方便我们快捷的取。
‘‘‘
request.method # 确认请求的方式
request.POST # 获取用户POST提交的普通数据,不包含文本
.get() # 只获取列表最后一个元素。
.getlist() # 将列表整个取出。
request.GET # 获取用户get请求数据。用法同上。
django链接数据库
# 1.首先配置文件中的配置。
将DATABASES中的配置进行修改。
DATABASES = {
‘default‘: {
‘ENGINE‘: ‘django.db.backends.mysql‘,
‘NAME‘: ‘info‘,
‘USER‘: ‘root‘,
‘PASSWORD‘: ‘123456‘,
‘HOST‘: ‘127.0.0.1‘,
‘PORT‘: 3306,
‘CHARSET‘: ‘utf8‘,
}
}
# 2. 代码声明,需要在任意的init文件下输入两行命令告诉django使用pymysql链接。
import pymysql
pymysql.install_as_MySQLdb()
django ORM
ORM:对象映射关系,将数据库表的数据通过对象的操作方式展示出来。
类================表
对象==============记录
对象属性=======记录某个字段对应的值
在应用下的models.py中书写一个类。
class Info(models.Model): # 括号内的models.Model必须要被继承
username = models.CharField(max_length=32, verbose_name=‘姓名‘)
password = models.CharField(max_length=32, verbose_name=‘密码‘)
# 如果不定义一个主键,会默认自动创建一个id字段的主键。
# 但凡涉及到数据库中的数据的更改,必须使用一下这两条命令进行更新。
python manage.py makemigrations # 将命令记录下来
python manage,py migrate # 将记录下来的操作执行,更改数据库
CharField必须要指定max_length参数 不指定会直接报错
verbose_name该参数是所有字段都有的 就是用来对字段的解释
# 字段的增删改:在models.py中的类中的操作
增:可以直接再类内增加一个可以为空的字段,或者设置了默认值的字段
改:直接修改代码然后执行数据库迁移命令
删:注释掉字段执行迁移命令。注意,一旦执行之后字段数据会丢失。
# 数据的增删改查:在views.py中对数据库中的数据进行的操作
查:
res = models.User.objects.filter(筛选条件).first()/last()
all_res = models.User.objects.all() # 查询结果是多个的话,使用all方法
‘‘‘
返回值是列表套数据对象的格式,支持索引和切片,一般会采用first/last的方法。得到具体数据的对象
此处的filter是过滤的意思,相当于数据库中的where筛选条件。
‘‘‘
增:res = models.User.objects.create(username=username,password=password)
另外一种方式是先通过类创建一个对象,然后在将对象保存到数据库中。
user_obj = models.User(username=username,password=password)
user_obj.save() # 保存数据
删:delete()
res = models.User.objects.filter(id=user_id).delete()
案例:登陆验证步骤
1、创建django项目
命令行:手动创建templates文件夹,然后在setting中的DIRS添加路径
Pycharm:无需配置
2、创建app:
pycharm:在创建完app之后,需要在settings中进行注册
3、在urls里添加路由对应关系,在app内的views编写对应的视图函数
4、静态文件的配置
1、创建static文件
2、settings中设置路径,添加STATICFILES_DIRS=[os.path.join(BASE_DIR,‘static‘)]
3、在html文件中的前几行引入样式,两种方法。
以/static/开头 或者 {% load static %}
5、连接数据库
1、settings更改
2、init输入替换代码
3、在app里面定义类
6、views内获取前端输入和数据库中匹配内容
1、前端输入须使用post
2、获取内容是一个对象,
3、数据库匹配内容是一个列表嵌套对象
7、校验数据,然后进行判断返回内容。
django ORM如何创建表关系
表关系一共有三种:多对多、一对多、一对一
# 一对多
publish = models.ForeignKey(to=‘Publish‘)
# 多对多:会默认创建第三张虚拟表,用来存它们之间的关系
authors = models.ManyToManyField(to=‘authors‘)
# 一对一
authordetail = models.OneToOneField(to=‘authors‘)
# pycharm会自动在一对多和一对一的外键的末尾添加一个_id
django请求生命周期流程图(很重要)
路由层
# 路由匹配
在路有层urls.py中,内部的路有关系。
url(r‘^index‘,views.index)
‘‘‘
第一个参数代表的是正则表达,一旦找到符合路由的内容,就会执行其后的函数。
如果第一遍找不到的话,会自动加一个斜杠在匹配一次
APPEND_SLASH = True/False 更改自动加斜杠匹配二次的设置
‘‘‘
# 无名分组/有名分组
分组就是将某一段正则表达式用小括号起来,然后会将括号内匹配到的内容差U年底给视图函数作为参数。
有名分组会将匹配到的内容作为关键字参数传递,在视图函数中使用参数名作为参数
url(r‘^index/(?P<参数名>/d+)‘,views.index)
无名分组会将匹配到的内容作为参数传递,在视图函数中可任意指定参数名,
url(r‘^index/(/d+)‘,views.index)
# 反向解析:通过某些方法得到一个结果,透过该结果可以直接访问对应的视图函数。
# 1. 首先给url起一个别名。
url(r‘^index‘,views.index, name=‘xxx‘)
# 2.在前端后端分别进行反向解析
<a href=‘{% url ‘xxx‘ %}‘>链接</a> # 前端
from django.shortcuts import reverse # 后端需要先导入
reverse(‘xxx‘)
# 两者结合起来:分组+反向解析
# 一般情况下都是放的数据的主键值,方便进行查找数据库对象
url(r‘^index/(d+)‘, views.index, name=‘xxx‘)
# 前端使用
{% url ‘xxx‘ 实参 %}
# 后端使用
reverse(‘xxx‘,args=(实参, ))
路由分发
django每一个app都可以有自己的templates文件夹,urls.py以及static文件夹。因此可以进行多人共同开发。每个人只需要写自己的app。
当写好自己的app以后,组长只需要将各自的app统一整合在一起,然后注册所有的app,就可以进行路由分发了。
在路由分发之后,总路由只和app有对应关系,而不是直接和视图函数对应。判断属于某一个app然后进行分发。
# 1.路由分发:这是将url匹配关系转到各自的app。
from app01 import urls as app01_urls
from app02 import urls as app02_urls
urlpatterns = [
url(r‘^app01/‘, include(app01_urls)) # 第一种方式,只要前缀匹配上,就交给该app
url(r‘^app01/‘, include(‘app01.urls‘)) # 第二种:利用字符串的形式。省略导入语句
]
名称空间
假设两个app都有‘index‘路由,如果进行反向解析,是不能自动分析出是哪一个路由关系的
有两种解决方式:
# 1. 使用名称空间:这是在总路由中书写
url(r‘^app01/‘,include(‘app01.urls‘,namespace=‘app01‘))
url(r‘^app02/‘,include(‘app02.urls‘,namespace=‘app02‘))
# 再进行反向解析的时候
reverse(‘app01:reg‘)
reverse(‘app02:reg‘)
{% url ‘app01:reg‘ %}
{% url ‘app02:reg‘ %}
# 2. 还有一种就是只要保证名字不冲突就好,可以在别名前面加上`app名_`的方式,在app中书写
urlpatterns = [
url(r‘^reg/‘,views.reg,name=‘app01_reg‘)
]
伪静态
可以将一个动态网页以html结尾伪装成一个静态网页,可以增大搜索概率。
虚拟环境
创建一个虚拟环境类似于下载了一个纯净的python解释器,一般创建一个项目的时候就要是用一个纯净的解释器,好确定使用的一些模块版本等等。
django版本区别
1. 1版本用的是url方法,2和3版本使用的是path方法
url() 第一个参数支持正则
path() 第一个参数不支持正则
re_path 2和3版本中这个方法等价于url
2.path支持五种转换器,不够用也可以自定义
path(‘index/<int:id>/‘,index) # 将第二个路由先转成整型,在传递给后面的视图函数
str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
int,匹配正整数,包含0。
slug,匹配字母、数字以及横杠、下划线组成的字符串。
uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
path,匹配任何非空字符串,包含了路径分隔符(/)(不能用?)
3.自定义转换器???
先定义,在注册
视图层
三板斧:Httpresponse, render, redirect
HttpResponse(‘返回前端的字符串‘)
render(request, ‘返回的页面‘, locals()) # locals可以将函数的名称空间给前端。
redirect(‘url‘) # 重定向
视图函数必须要返回一个HttpResponse对象,看源码就会发现。
JSONResponse对象
‘‘‘
前后端数据交互需要使用到json作为过渡,实现跨语言传输数据。
前端序列化
JSON.stringify() json.dumps()
JSON.parse() json.loads()
‘‘‘
import json
from django.http import jsonResponse
form表单上传文件及后端如何操作
‘‘‘
form表单上传文件类型的数据
1. method必须指定post
2. enctype换成formdata
‘‘‘
def ab_file(request):
if request.method == ‘POST‘:
print(request.FILES) # 获取文件数据
file_obj = request.FILES.get(‘file‘) # 文件对象
return render(request,‘form.html‘)
request对象方法
"""
request.method
request.POST
request.GET
request.FILES
request.body # 原生的浏览器发过来的二进制数据 后面详细的讲
request.path
request.path_info
request.get_full_path() 能过获取完整的url及问号后面的参数
"""
FBV 和CBV
# 视图函数既可以是函数,也可以是类
‘‘‘
FBV:视图函数是一个函数。
CBV:视图函数是一个类,类内部定义的是同名的不同请求方式的函数。本质上也是FBV
内部机制就是通过url找到类,然后获取到请求的方式,通过反射,执行类内部的自定义请求的同名函数。
‘‘‘
from django.views import View
class MyClass(View):
def get(self,request):
return HttpResponse(‘get请求来会执行此句‘)
def post(self,request):
return HttpResponse(‘post请求来会执行此句‘)
url(r‘^index‘, views.MyClass.as_view()) # 加括号之后,在加载的那一刻就会执行。
‘‘‘
内部执行原理:
1. 首先加括号会执行,然后内部判断请求方式,返回as_view内部定义的view函数内存地址。
2. 被触发之后,就会执行内部view函数,然后产生自定义类的对象,根据请求方式反射,然后运行对应的函数。
‘‘‘
‘‘‘
重点:往后看源码较多,一定要时刻提醒自己面向对象的属性查找顺序以及当前的self指的是谁
‘‘‘
模板语法
‘‘‘
模板语法就是将后端的数据接收并在前端展示、替换等等。
{{ }}: 变量相关都是使用两个大括号
{% %}: 逻辑相关的一般使用
1.当数据在前端被展示的时候,会触发__str__方法哦
2.基本上Python所有的数据类型都能够通过{{ }}的语法展示出来
3.传递的函数也必须是无参函数,而且会自动加括号进行调用
4.针对类、变量等等,内部都会做出判断能够调用的都加括号进行调用
5.django的取值方式只能是点点点,也可以使用索引,但是不能够进行混用
‘‘‘
{{ dict.username }}
{{ list.6 }}
# 过滤器类似于模板语法的内置方法
‘‘‘
{{数据|过滤器:参数}}
‘‘‘
{{ s|length }} # 统计s长度
{{ b|default:‘1‘ }} # 如果b为假,那么就展示default后的值。
{{ file_size|filesizeformat }} # 可以进行文件大小的单位转换
{{ current_time|date:‘Y-m-d‘ }} # 日期格式
{{ l|slice:‘0:4:2‘ }} # 切片操作,支持步长
{{ info|truncatechars:9 }} # 切取字符,包含三个点
{{ egl|truncatewords:9 }} # 切取单词
{{ info|cut:‘A‘ }} # 移除所有的字符A
{{ l|join:‘+‘ }} # 拼接操作
{{ num|add:‘101‘ }} # 可以进行数字的相加,也可以拼接字符串,但不可混用
{{ 前端代码|safe }} # 转义,可以执行内部的前端代码
# 在前端使用转义
{{ |safe }}
# 在后端使用转义
from django.utils.safestring import mark_safe
res = mark_safe(‘<p>我这能够显示的</p>‘)
标签
# for循环
{% for foo in l %}
<p>{{ forloop }}</p>
<p>{{ foo }}</p> 一个个元素
{% empty %}
<p>for循环的可迭代对象内部没有元素 你就能看到我了</p>
{% endfor %}
‘‘‘
forloop的结果
{‘parentloop‘: {}, ‘counter0‘: 0, ‘counter‘: 1, ‘revcounter‘: 6, ‘revcounter0‘: 5, ‘first‘: True, ‘last‘: False}
其中first和last是确定元素是否在开头或者结尾,count0是元素的下标,counter是元素是第几个
‘‘‘
# if判断
{% if b %}
<p>满足条件执行</p>
{% elif s%}
<p>。。。。</p>
{% else %}
<p>都不满足执行</p>
{% endif %}
# with起别名
{% with d.hobby.3.info as nb %}
<p>{{ nb }}</p>
在with语法内就可以通过as后面的别名快速的使用到前面非常复杂获取数据的方式
<p>{{ d.hobby.3.info }}</p>
{% endwith %}
自定义过滤器、标签、inclusion_tag
‘‘‘
首先需要满足的条件“:
1.应用下创建一个templatetags文件夹。
2.文件夹下创建任意名称的py文件:mytags.py
3.在该文件内必须填写两句代码
from django import template
register = template.Library()
‘‘‘
# 自定义过滤器:参数最多只能有两个。
@register.filter(name=‘过滤器名字‘)
def my_sum(v1,v2):
return v1+v2
# 使用
{% load mytags %}
<p>{{ n|过滤器名字:100 }}</p>
# 自定义标签
@register.simple_tag(name=‘标签名‘)
def index(a,b,c,d):
return ‘%s-%s-%s-%s‘%(a,b,c,d)
# 使用:参数用空格隔开
<p>{% 标签名 ‘jason‘ 123 123 123 %}</p>
# 自定义inclusion_tag
‘‘‘
执行流程:
先定义一个方法
在页面上调用该方法,并传值
该方法生成一些数据传给html页面
之后将渲染好的结果放到调用位置
‘‘‘
@register.inclusion_tag(‘目标html文件‘)
def left(n):
data = [‘第{}项‘.format(i) for i in range(n)]
return {‘data‘:data} # 第一种方式
return locals() # 第二种方式
{% left 5 %}
‘‘‘
当html页面某个位置需要传参数可以动态渲染出来,并且在多个页面使用,可以考虑做成inclusion_tag形式
‘‘‘
模板的继承
‘‘‘
当一些网站整体页面不改变 只有一些局部地区改变的话 就可以使用继承。
当想要继承一个模板的时候,先将自己的html清空,然后输入关键句:
{% extends ‘继承的父html‘ %}
这样就会拿到一个一毛一样的页面了,如果想做出自己的改变,就需要在父html内用block先规定好可以做出改变的区域。一般情况下会有三个block区域:cssjscontent
{% block css %}
{% endblock %}
{% block js %}
{% endblock %}
{% block conten %}
{% endblock %}
除了block区域之外的部分都不能进行修改,子html想要进行修改的话,也需要声明同样的语句,来进行更改。比如想要修改content区域。
{% block conten %}
这些都是我想要改的标签
{% endblock %}
‘‘‘
模板的导入
# 将页面的某个部分当做模块的形式,在需要的时候可以导入。
{% include ‘模块的名字‘ %}
模型层
# 单表数据的增删改查
# 增:models.User.objexts.filter(pk=3).first()
# 删:mdoels.User.objects.filter(pk=3).delete()
# 该:models.User.objects.filter(pk=3).update(name=‘tom‘)
# 必知必会13条
all() # 查询所有的数据
filter() # 带过滤条件的查询
get() # 直接拿数据对象,但是数据不存在则报错。
first() # 拿到queryset第一个元素对象
last() # 拿到queryset最后一个元素
values() # 可以指定获取的数据字段 <QuerySet [{‘name‘: ‘jason‘, ‘age‘: 18}, {‘name‘: ‘egonPPP‘, ‘age‘: 84}]>
values_list() # 列表套元祖 <QuerySet [(‘jason‘, 18), (‘egonPPP‘, 84)]>
distinct() # 去重,主要是针对一模一样的数据,不能忽略主键
Order_by() #分组,字段加-,代表降序
reverse() # 反转,前提是已经排过序了
count() # 统计当前数据的个数
exclude() # 排除在外
exists() # 返回的是布尔值
‘‘‘
针对queryset对象,可以使用.query的方式查看器执行的sql原生语句。
第二种方式:去配置文件中配制一下即可。针对任意类型。
‘‘‘
LOGGING = {
‘version‘: 1,
‘disable_existing_loggers‘: False,
‘handlers‘: {
‘console‘:{
‘level‘:‘DEBUG‘,
‘class‘:‘logging.StreamHandler‘,
},
},
‘loggers‘: {
‘django.db.backends‘: {
‘handlers‘: [‘console‘],
‘propagate‘: True,
‘level‘:‘DEBUG‘,
},
}
}
测试脚本
‘‘‘
指向测试某一个py文件的内容,可以不用书写前后端交互的形式,可以写在tests.py文件在即可
但是需要一些准备工作。
1.去manage.py拷贝前4行代码
2.自己写两行代码
import django
django.setup()
然后就可以在下方测试单个py文件了
‘‘‘
神奇的双下划线查询
res = models.User.objects.filter(age__gt)
__gt 大于
__gte 大于等于
__lt 小于
__lte 小于等于
__range 范围
__in 或
__contains 含有(不忽略大小写)
__icontains 含有(忽略大小写)
__startswith 首字母
__endwith 尾字母
__month 查询时间
__year
一对多外键增删改查
# 一对多外键增删改查
# 增:可以直接写实际字段,也可以写虚拟对象
models.User.objects.create(title=‘雨夜小故事‘, publish_id=1)
publish_obj = models.User.objects.filter(pk=3).first()
models.User.objects.create(title=‘雨夜小故事‘,publish=publish_obj)
# 删
models.Publish.objects.filter(pk=2).delete()
# 修改
models.Book.objects.filter(pk=1).update(pubish_id=2)
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.filter(pk=1).update(publish=publish_obj)
多对多外键增删改查
# 如何给书籍添加作者? add()括号内可以传主键值也可以传对象,支持多个
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors # 可以理解为已经到了第三张表了。
book_obj.authors.add(1,2,3) # 添加了1,2,3三个作者
# 删 remove(),同add()
book_obj.remove(2)
book_obj.remove(author_obj)
# 改 set([1]) 括号内必须是一个可迭代对象,元素可以是数字,对象,可以多个
book_obj.authors.set([1,2,3])
# 清空
book_obj.authors.clear()
正反向的概念
‘‘‘
正向:外键在A表手上,关联着B表,A主动查B就是正向
反向:A被B查就是反向
正向查询按字段,反向查询按表名小写__set
当查询结果是多个的话,就需要在后面使用.all()方法
正反向的概念应用于表对象之间的查询,
双下划线的概念用于某个字段的查询,且在过滤条件的时候就需要‘主键所在表名__字段名’
‘‘‘
# 首先是基于对象的跨表查询
# 正向
models.Book.objects.filter(pk=3).first().publish # 通过书籍查出版社
models.Book.objects.filter(pk=4).first().authors.all() # 书籍查作者,多个用all
# 反向
models.Publish.objects.filter(pk=1).first().book_set.all()
# 基于双下划线的查询。
# 正向
models.Book.objects.filter(title=‘雨夜小故事‘).values(‘author_detail__phone‘,name)
# 反向
models.authorDetail.objects.filter(author__name=‘tom‘).first()
聚合查询
‘‘‘
聚合查询 关键字为aggregate:单词聚合的
聚合查询通常情况下都是配合分组一起使用的
PS:只要是跟数据库相关的模块,一般都在django.db.models内部,要么就是django.db
‘‘‘
from django.db.models import Max, Min, Sum, Count, Avg
# 计算所有书的平均价格
res = models.Book.objects.aggregate(Avg(‘price‘),Count(‘price‘)
分组查询
‘‘‘
分组查询的关键字是annotate:单词是注解的意思
分组的特点:分组之后只能获取到分组的依据,组内其他字段都无法直接获取
严格模式:ONLY_FULL_GROUP_BY
‘‘‘
# 统计每一本书的作者个数 先按照书进行分组
models.Book.objects.annotate() # models后面是什么就是按照什么进行分组。
res = models.Book.objects.annotate(author_num=Count(‘author‘))
‘‘‘
此时的res是根据Book进行分组,annotate内部的参数是重新为所得到的对象增加一个新的自定义字段,存储着作者的个数。
‘‘‘
# 如果想按照指定的字段分组该如何处理呢?
models.Book.objects.values(‘price‘).annotate()
# 此时的annotate会去找Book内的price字段进行分组。
F与Q查询
‘‘‘
F查询:能够直接获取到列表中某个字段对应的数据。可以进行同一对象的两个字段的比较。
Q查询:正常情况在filter内部的条件是and关系,有了Q查询,那么就可以进行与或非的关系查询了。
‘‘‘
from django.db.models import F, Q
# F查询
# 查询卖出数大于库存数的书籍(卖出数和库存数是表的两个字段)
models.Book.objects.filter(maichu__gt=F(‘kucun‘))
# 将所有书的价格提升500块
models.Book.objects.update(price=F(‘price‘)+500)
# 针对字符串的拼接是不可以直接进行的。直接进行拼接会变成空白
from django.db.models.functions import Concat
models.Book.objects.update(title=Concat(F(‘title‘), Value(‘爆款‘)))
# Q查询
res = models.Book.objects.filter(Q(maichu__gt=100),Q(price__lt=600)) and
res = models.Book.objects.filter(Q(maichu__gt=100)|Q(price__lt=600)) or
res = models.Book.objects.filter(~Q(maichu__gt=100)|Q(price__lt=600)) not
Q的高阶用法:能够将查询条件左边变成字符串的形式
q= Q() # 首先生成一个对象
q.connector = ‘or‘ # 默认关系为and,可以改为or
q.children.append((‘maichu__gt‘,100))
models.Book.objects.filter(q)
django如何开启事务
‘‘‘
事务:在同一事务内的sql语句一旦有一个出错,整个事务就会不成功。
回滚:rollback
确认:commit
‘‘‘
# 简单的开启事务
from django.db import transaction
try:
with transaction.atomic():
sql语句的一些python操作
except Exception:
...
orm常用字段及参数
‘‘‘
Autofield 主键字段 primary_key = True
Charfield 对应的是varchar,
IntegerField int类型
BigIntergerField 大的int型
DecimalField 小数类型
DateField date
EmailField varchar(254)
DatetimeField
auto_now: 每次修改数据的时候自动更新时间
auto_now_add:只在创建的时候记录时间,后续不会进行修改
BooleanField 布尔值类型,在数据库中存的是0、1类型
TextField(field) 存放大段文本类型
FileField
upload_to = ‘/data‘
给该字段传一个文件对象,会自动将文件保存到/data目录下然后将文件路径保存到数据库中
# 更多字段
直接参考博客:https://www.cnblogs.com/Dominic-Ji/p/9203990.html
# django还支持自定义字段
class MyCharField(models.Field):
def __init__(self,max_length,*args,**kwargs):
self.max_length = max_length
# 调用父类的init方法
super().__init__(max_length=max_length,*args,**kwargs) # 一定要是关键字的形式传入
def db_type(self, connection):
"""
返回真正的数据类型及各种约束条件
:param connection:
:return:
"""
return ‘char(%s)‘%self.max_length
# 自定义字段使用
myfield = MyCharField(max_length=16,null=True)
‘‘‘
# 外键字段及参数
unique = True
ForeignKey(unique=True) === OneToOneField()
db_index=True # 意味着此字段可以设置为索引
to_field #设置要关联表的字段 默认不写关联的就是另外一张主键字段
on_delete 当删除关联表中的数据时,当前表与其关联的行为。
数据库的优化查询
‘‘‘
only与defer
如果我们仅仅书写orm语句的话,在后面没有用到,那么就回不执行
only就是只取所跟的字段参数,要是查询表中其他的字段,需要再次走数据库
defer相反,如果查的是所跟字段参数,那么就回走数据库,其他字段则不需要走数据库
select_related :将有外键关联的两张表的数据连起来一次性读出来,全部封装给查询出来的对象,之后在进行数据的查询的时候,可以直接使用,无序数据库了。针对的是外键关系的表
res = models.Book.objects.select_related(‘authors‘) inner join关系
prefetch_related内部是子查询 将子查询的结果封装到对象中,
models.Book.objects.prefetch_related(‘publish‘)
‘‘‘
choices参数(数据库字段设计常见)
# 如果某个字段的不同结果能被列举出来,就可以使用choices参数
字段_choices = ((存放数据,代表含义),(),())
# 需要将choices参数放在定义之前。
gender_choices = (
(1,‘男‘),
(2,‘女‘),
(3,‘其他‘),
)
gender = models.IntegerField(choices=gender_choices)
# 首先存进数据库的数据要符合数据库存放的标准,其次如果情况没被列出,只要符合数据库该字段的要求就会被存放。
查询choices参数对应的意思的话,需要使用固定的语法
get_字段_display()
MTV与MVC模型
# MTV :django号称是MTV,但本质仍是MVC
M:models
T:templates
V:views
# MVC
M:models
V:views
C:controller
多对多的三种创建方式
# 全自动:利用Orm直接自动帮我们创建第三张表,不需要自己创建,可以使用外键的add,set,remove等方法,缺点是不扩展性差
# 手动:自己手动创建第三张表,扩展性好,但是代码比较繁杂,且不能使用orm提供的方法
class Book2Author(models.Model):
book = models.ForeignKey(to=‘Book‘)
author = models.ForeignKey(to=‘Author‘)
# 半自动:推荐,第三表同样自己创建,然后在每张表外键关联的字段添加参数。
class Book(models.Model):
name = models.CharField(max_length=32)
authors = models.ManyToManyField(to=‘Author‘,
through=‘Book2Author‘, # 填写第三张表
# 简化判断:当前表是谁 就把对应的关联字段放前面
through_fields=(‘book‘,‘author‘)
)
class Book2Author(models.Model):
book = models.ForeignKey(to=‘Book‘)
author = models.ForeignKey(to=‘Author‘)
# 可以使用正反向查询,但是不能使用add,set,remove,clear。
Ajax详解
‘‘‘
主要作用就是异步提交、局部刷新。动态获取用户数据进行更新,但是不刷新页面。
向后端发出请求的方式一共有4种。
1.浏览器地址栏直接输入url回车 GET请求
2.a标签href属性 GET请求
3.form表单 GET请求/POST请求
4.ajax GET请求/POST请求
当前学习的是jQ封装的版本 在使用的时候需要确保导入了JQ。
‘‘‘
$(‘#btn‘).click(function () {
// 朝后端发送ajax请求
$.ajax({
// 1.指定朝哪个后端发送ajax请求
url:‘‘, // 不写就是朝当前地址提交
// 2.请求方式
type:‘post‘, // 不指定默认就是get 都是小写
// 3.数据
{#data:{‘username‘:‘jason‘,‘password‘:123},#}
data:{‘i1‘:$(‘#d1‘).val(),‘i2‘:$(‘#d2‘).val()},
// 4.回调函数:当后端给你返回结果的时候会自动触发 args接受后端的返回结果
success:function (args) {
{#alert(args) // 通过DOM操作动态渲染到第三个input里面#}
{#$(‘#d3‘).val(args)#}
console.log(typeof args)
}
})
})
‘‘‘
如果用的是HttpResponse返回的数据,那么回调函数不会自动进行反序列户。
如果用的是JsonResponse返回的数据,回调函数会自动进行反序列化。
HttpResponse解决方式
1.自己在前端利用JSON.parse()
2.在ajax里面配置一个参数:dataType:json
(后面再讲)
‘‘‘
前后端传输数据的编码格式(contentType)
# 针对Post请求数据的编码格式。
‘‘‘
get请求数据就是直接放在url后面的,问号开头,&做分隔
‘‘‘
前后端传输数据的编码格式
1. urlencoded 默认都是为urlencoded
2. formdata 普通键值对还是会被解析到urlencoded,但是文件会被解析到request.FILES中。
3. json form表单没有办法发送Json格式,只有ajax可以
ajax发送json格式的数据
首先要确保发送的数据确实是json格式数据
1. 添加参数:contentType:‘application/json‘。作用就是指定编码格式。
data:JSON.stringify({‘username‘:‘jason‘,‘age‘:25}),
2. 后段不会帮忙处理json格式的数据,需要自己在request.body获取并处理
ajax发送文件
ajax发送文件需要接触js内置对象FormData.
1.生成一个FormData的对象
let fomdata_obj = new FormData();
2. 添加键值对
formdata_obj.append(key,value)
3.添加文件对象
formdata_obj.append(key,$(‘#d1‘)[0].filed[0])
4. 将对象基于ajax发送。
ajax发送文件必须指定两个参数:
contentType:false, 不需任何编码,后端自动识别
processData:false, 告诉浏览器不对数据进行处理
后端接受到数据之后,将普通的键值对解析到POST中,文件信息解析到FILES中。
django子代的序列化组件(drf做铺垫)
在前段获取到列表套字典格式的数据信息,可以依靠组件搞定。
from django.core import serializers
# 序列化
res = serializers.serialize(‘json‘,user_queryset)
ajax结合sweetalert
‘‘‘
一些弹框操作。
要学会如何copy粘贴并修改一些参数。
‘‘‘
事例:二次弹框
批量插入
# bulk_create:是一个批量插入的方法,可以减少操作时间
需要先将读取出来的数据封装成一个个对象,然后放到一个列表中,在当做参数传入bulk_create。可以减少操作时间
以上是关于django框架的主要内容,如果未能解决你的问题,请参考以下文章
django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TABLESPACE的解决办法(转)(代码片段
django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TABLESPACE的解决办法(转)(代码片段