zoukankan      html  css  js  c++  java
  • 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。可以减少操作时间
    
  • 相关阅读:
    SQL数据去重复 Distinct 和 row_number() over()
    Excel闪退问题解决
    SQL Server 修改服务器登录名称以及密码
    从底层角度看ASP.NET-A low-level Look at the ASP.NET Architecture
    MD5加密
    MD5实例化异常 未能执行FIPS验证加密算法
    JDBC(上)
    自学MySQL第二天
    自学MySQL第一天
    自学JavaWeb第五天jQuery进阶
  • 原文地址:https://www.cnblogs.com/liqianxin/p/13059224.html
Copyright © 2011-2022 走看看