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制作一个服务器运行之后,将浏览器当做客户端进行链接。

  1. 输入ip:port就是发起链接请求,如(127.0.0.1:8000/index) 此时会按照请求格式发送一个请求。
  2. 服务端接受到请求之后,会按照响应的格式返回一个响应。

基于这样的思路,我们就可以自己写一个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文件了。

首先了解一下网页的分类:

  1. 静态网页:跟后端数据没有交互,数据一层不变。
  2. 动态网页:跟后端交互数据,数据实时获取的。

获取的数据是在数据库中的,我们可以通过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 rest_framewok框架的基本组件

[TimLinux] Django 信号

django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TABLESPACE的解决办法(转)(代码片段

django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TABLESPACE的解决办法(转)(代码片段

text 来自Codyhouse框架的Browserlist片段源代码

使用实体框架迁移时 SQL Server 连接抛出异常 - 添加代码片段