十二周周末小结结

十二周总结


Django路由层

1.Django请求生命周期流程图

image-20221212212219273
1.路由匹配
django2.x以及以上,urls.py中path第一个参数写什么就匹配什么
django1.x第一个参数是正则表达式
路由匹配本质:path第一个参数写什么就匹配什么
# 无论什么版本,django都自带自动加`/`并重定向的功能,可以看到当user_list在路由匹配中找不到的时候,django会自动添加`/`并重定向

# 该重定向功能可以取消,在settings.py中,将APPEND_SLASH改为False

2.转换器
转换器捕捉info的时候,会将info转换成固定类型,然后当成参数传入视图函数,形式如下
        str:匹配除路径分隔符外所有的非空字符串
        int:匹配0或者任意正整数
        slug:匹配任意一个由字母或数字组成的字符串
        uuid:匹配格式化之后的UUID
        path:匹配完整的URL路径
        
3.正则匹配re_path        
正则匹配的原则:只要第一个正则表达式能够从用户输入到路由中匹配到数据就算匹配成功,就会立刻从停止在路由层匹配,而直接执行对应的视图函数        
        re_path('^test/$', views.test)  
# 限制开头和结尾,精准匹配/test/

2.反向解析

1.通过起一个别名,可以反向解析出一个结果,这个结果可以访问到一个对应到路由,可以访问到对应的一个视图函数(减少耦合,动态匹配)

2.基本使用
    1.路由匹配关系起别名
        path('login_01', views.login, name='login_view')
    2.反向解析语法
        html页面模板语法  {% url 'login_view' %}
        后端语法          reverse('login_view')
        
3.动态路由的反向解析
	path('func1/<str:others>/', views.func1_func, name='func1_view')
 	html页面上模板语法 {% url 'func1_view' 'jason' %}  # 需要一个参数与接收到的路由的第二个参数对应
 	后端语法		  reverse('func1_view', args=('嘿嘿嘿',)) 

3.路由分发

1.简介
基于Django开发应用,Django支持每个应用都可以有自己独立的路由层urls.py文件、静态文件static文件夹、模版层templates文件夹。


2.路由分发的实现
# 在子路由中
from django.urls import path
from app01 import views

urlpatterns = [
    path('index/', views.index_func),
]

# 总路由
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('app01/', include('app01.urls')),
]

4.名称空间

当我们在Django项目中建立了多个应用,并在路由对应关系中出现了相同的别名的时候,正常情况下的反向解析是无法自动识别前缀的,如果想找正常识别区分有两种方式

(1)方式一:名称空间
    # 子路由app01和app02中都有
    path('index/', views.index, name='indes_view')
    # 总路由
    path('app01/', include('app01.urls', 'app01'), namespace='app01'),
    path('app02/', include('app02.urls', 'app02'), namespace='app02')
    # 反向解析
    reverse('app01:index_view')
    reverse('app02:index_view')
    
(2)方式二:其别名的时候加前缀
多个应用子路由中,给路由和视图函数的对应关系起名的时候,可以用作用名作为别名的前缀,防止别名重复导致的冲突

    path('index/', views.index, name='app01_indes_view')
    path('index/', views.index, name='app02_indes_view')

Django视图层

1.三大方法

参数 内容
request 用于生成响应的请求对象
template_name 要使用的模板的完整名称,可选的参数
context 添加到模板上下文的一个字典 默认是一个空字典 如果字典中的某个值是可调用的,视图将在渲染模板之前调用它 局部命名空间变量(字典形式从换入),或locals()函数

2.JsonResponse

虽然python中为我们准备了json格式的序列化的模块json,但是当我们通过自带的json模块进行序列化展示到浏览器上的时候,浏览器的渲染没有亲和力,也不会当成json字符串渲染

JsonResponse源码学习

image-20221213203338499

通过源码的阅读,我们可以发现我们可以通过设置其中参数,改变我们序列化的限制。

  • safe=False改变只能序列化字典
def json_func(request):
    l1 = [11, 22, ['aaaa'], ('a',)]
    return JsonResponse(l1, safe=False)

image-20221213203647351

  • 正常显示出中文

    json_dumps_params={'ensure_ascii': False}

def json_func(request):
    data_dict = {'test_content': 'about JsonResponse ', 'age': 22, '爱好': '放空'}
    # l1 = [11, 22, ['aaaa'], ('a',)]

    return JsonResponse(data_dict, json_dumps_params={'ensure_ascii': False})

3.request对象获取文件

请注意只有在请求是通过 POST 提交且提交的 <form> 表单有 enctype="multipart/form-data" 属性的时候,[request.FILES] 才会包含文件数据,否则的话, request.FILES 是空的。

1.前端html页面:form表单上传文件
form表单携带文件类型的数据需要做到以下几点
  1.method必须是post 
  2.enctype属性改成multipart/form_data
  
2.后端:request.FILES获取文件类型的数据  
  1.# 拿到文件对象
  request.FILES.get('file')  
  2.# 推荐加上chunks方法 其实跟不加是一样的都是一行行的读取
  with open(file_obj.name, 'wb') as destination:
            for chunk in file_obj.chunks():  

4.FBV与CBV

视图函数既可以是函数也可以是类

1.FBV(Function Bases View)

基于函数的视图

def index(request):
  return HttpResponse对象

2.CBV(Class Bases View)

基于类的视图,用面向对象的方法写视图类

优点:比FBV灵活,只需要定义与请求方法同名的方法(get和post请求),会自动根据请求方法的不同自动匹配对应的数据,

Django模板层

1.模板语法传值

1.精准传值:通过字典的形式传值
    return render(request, 'indexpage.html', {'i': i, 'd1': d1, 'l1': l1})
    精准传值,不浪费资源;但是针对数据量大的数据,传值麻烦
    
2.统一传值:locals()
    return render(request, 'indexPage.html', locals())
    locals()方法会将所有数据数据一起以同名字典的形式发送给html页面渲染好了之后发送给浏览器

2.模版语法的传值特性

(1)python基本数据类型,对象名都可以传递(且可以点方法)

(2)文件对象也可以展示,并支持调用文件的方法如read write

(3)函数名传递过去的时候,也会自动加括号执行,但是不支持传参

(4)类名传过来会自动加括号调用对象传过来还是对象

3.过滤器

1.|add

i = 666
{{ i|add:3 }}

2.|length

返回值的长度,作用于字符串和列表。

{{ s|length }}

3.|slice切片

4.|date格式化

{{ value|date:"Y-m-d H:i:s"}}

5.|safe

value = "<a href='#'>点我</a>"
{{ value|safe}}
我们可以通过过滤器“|safe”的方式告诉Django这段代码是安全的不必转义

6.|truncatechars

{{ value|truncatechars:9}}
如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾。

7.|truncatewords

{{ value|truncatewords:9}}
在一定数量的字后截断字符串。

8.|filesizeformat

{{ value|filesizeformat }}
将值格式化为一个 “人类可读的” 文件尺寸 (例如 `'13 KB'`, `'4.1 MB'`, `'102 bytes'`, 等等)。

4.模版层标签

1.if判断
  {% if d1 %}
      内容块
      ...
  {% endif %}

2.for循环
  {% for foo in d1 %}
      <p>{{ foo }}</p>
  {% endfor %}
  
3.with标签:起别名
复杂数据获取之后需要反复使用,可以通过 with起别名,但是这个别名,只支持在with语法中使用
  {% with d1.hobby.1.a1 as h %}
      {{ h }}
  {% endwith %}
  
4.取值
从技术上讲,当模板系统遇到一个点,它会尝试下面的动作,顺序如下:

- 字典查询
- 属性或方法查找
- 数字索引查找

# 字典查询
{{ d1.name }}

# 属性或方法查找
<p>{{ d1.items }}</p>
<p>{{ d1.values }}</p>

# 数字索引查找
<p>{{ l1.1 }}</p>

5.模板的继承和导入

1.继承
模板继承:先构建一个基本的“骨架”模板 base.html,其中包含其他页面的的所有公共元素并在母版中定义子模板可以替换的块

(1)创建一个`base.html`包含网站主要外观的模板
  {% block 区域名称%}
      母版页面上标记的可修改的部分
  {% endblock %}
(2)创建子页面`section.html`继承母版,并导入子页面
  {% extends 'home.html' %}

  {% block 母版上的区域名称 %}
        子页面中自定义部分
  {%  endblock %}

2.导入
我们将某个html页面的部分提前写好,之后其它html页面都可以使用
  {% include '提前写好的部分的文件名(带后缀)' %}

Django模型层

1.django自带的sqlite3数据库对时间字段不够敏感,而且功能也少,所以我们习惯切换成常见的数据库
2.对于django,ORM不会自定帮我们创建库,所以需要我们提前准备好库
3.单独测试Django的某个功能层
    Django默认是不允许单独测试某个py文件的,如果我们想要测试可以使用下面的两种方法
        1.pycharm提供的python console 中写代码测试,但是这个是模拟终端的,写的代码不会保存,建议一些简单的功           能可以在这里测试
        2.自己搭建一个测试环境,可以使用自带的test.py文件或者是自己重新创建一个
            1.拷贝manage.py前四行代码
            2.自己再加两行代码
                import django
                django.setup()
4.dajngo ORM的底层还是SQL语句,可以查看
    1.如果我们拿到的是一个Queryset对象,那么我们可以直接通过点query的方式查看SQL语句
    2.如果我们想查看所有ORM底层的SQL语句,可以在配置文件中添加日志记录,之后会将SQL语句打印到pycharm终端上
        LOGGING = {
            'version': 1,
            'disable_existing_loggers': False,
            'handlers': {
                'console':{
                    'level':'DEBUG',
                    'class':'logging.StreamHandler',
                },
            },
            'loggers': {
                'django.db.backends': {
                    'handlers': ['console'],
                    'propagate': True,
                    'level':'DEBUG',
                },
            }
        }

2.模型层常用关键字

1.create()
创建数据并且直接获取当前创建的数据对
models.User.objects.create(name='bo', age=22)

2.filter()
根据条件筛选数据,结果是QuerySet 列表套对象,括号内支持多个条件,但是是and关系
models.User.objects.filter(name='duo')

3.first()  last()
使用索引取值没有的情况下会报错,但是使用first last方法,没有数据的情况或返回none不会报错

4.update()
根据筛选条件更新不同的个数
# 批量更新
models.User.objects.filter().update()  

# 单个更新
models.User.objects.filter(id=1).update(age=22)  

5.delete()
根据筛选条件删除不同的个数
models.User.objects.filter().delete()      批量删除
models.User.objects.filter(id=1).delete()  单个删除

6.all()
查询所有数据
models.User.objects.all()

7.values()
指定字段获取数据,结果是<QuerySet [{},{},{}]>   列表套字典


8.values_list()
根据指定字段获取数据,结果是Queryset [(),()] 列表套元组

9.distinct()  去重,数据必须完全一致,如果有主键则用不了

10.order_by()
根据指定条件排序,默认是升序,条件前面加减号则是降序
models.User.objects.all().order_by('age')

11.get()
根据条件筛选数据并直接获取到数据对象,数据不存在拿不到数据,则会报错
models.User.objects.get(id=1)

12.exclude()排除,去反操作
models.User.objects.exclude(age=22)

13.reverse()
颠倒顺序,但是被操作的顺序必须需要提前排序完成
models.User.objects.order_by('age').reverse()

14.count()
统计结果集中数据的个数
models.User.objects.filter(age=22).count()

15.exists()
判断结果集中是否含有数据,如果有则返回True 没有则返回False
models.User.objects.filter(id=1).exists()

3.ORM执行查询sql语句

1.方式一:通过ORM执行sql语句
models.User.objects.raw('select * from app01_user')

2.方式二:通过django封装好了的pymysql模块执行sql语句
# 导入connection,产生游标对象cursor
from django.db import connection
cursor = connection.cursor()
cursor.execute('select name from app01_user;')

4.神奇的双下划线方法

1.__gt大于
2.__lt小于
3.__gte`大于等于和`__lte`小于等于
4.__in成员运算
5.__range范围之间查询
6.__contains和 __icontains模糊查询
7.查询时间关键字
  __year年
  __month月
  __day日
  __hour时

5.ORM外键字段的建立

1.mysql中的外键关系
  一对多:外键字段建立在多的一方
  多对多:外键字段统一建在第三张关系表中,在django中不用自己创建,只需创建外键后django会帮我们自动创建一个表出来
  一对一:建在任何一方都可以,但是应该建立在热数据表也就是查询频率较高的表中
  
2.orm外键字段的创建

(1)一对多,ORM与MySQL
orm会自动帮我们把外键字段后加_id的后缀,所以我们不用自己添加_id后缀

(2)多对多 
ORM比MySQL更多变化

ORM:外键字段可以直接建在某张查询频率较高的表中,在orm内部会自动帮我们创建第三张表,这个外键字段是虚拟字段在表中并不会显示,只是告诉orm帮我们创建第三张关系表
MySQL:自己创建第三张关系表并创建外键字段

(3)一对一
外键字段可以直接建在某张查询频率较高的表中

6.跨表查询

1.正反向查询的概念
正向查询
    从有外键字段的表查询关联表的数据
反向查询
    从没有外键字段的表查询关联表的数据
核心就是看外键字段

口诀
    正向查询按外键字段
    反向查询按表名小写
    
    
2.基于对象的跨表查询(子查询)
相当于mysql中的子查询
( 1)先根据已知条件获取到一个具体的数据对象
( 2)基于该数据对象运用正反向查询的口诀完成

4.基于双下划线的跨表查询
反向的口诀也使用与values或者values_list中使用

7.聚合查询

1.聚合函数:
		max min sum count avg
    在ORM中指出单独使用聚合函数,通过关键字aggregate
    
2.导入聚合函数
from django.db.models import Max,Min,Sum,Count,Avg
models.表名.onjects.aggregate(别名=Max('字段名'), 别名=Min('字段名'), 别名=Sum('字段名'), 别名=Avg('字段名'), 别名=Count('字段名'))

8.分组查询

1.通过关键字annotate,进行分组查询

2.分组依据
models.表名.objects.annotate()       按照表分组
models.表名.objects.values('字段名').annotate   按照values括号内指定的字段分组

3.语法
models.Book.objects.annotate(聚合函数分组一句).filter(筛选条件相当于having).values('字段名')

9.F查询与Q查询

# 导入F,Q
from django.db.models import F, Q

1.F查询
F查询为当前查询条件不明确,也需要从数据库中获取时使用的


2.Q查询
Q查询为执行条件之间的关系为与或非时使用的
posted @ 2022-12-18 19:12  Duosg  阅读(19)  评论(1编辑  收藏  举报