文章目录
- django进阶
- 内容回顾
- 1.模板
- 1.1 寻找html模板顺序
- ==1.2 模板处理的本质==
- 1.3 常用语法
- 1.4 内置函数
- 1.5 自定义模板功能
- 1.6 继承和母版
- 1.7 模板的导入
- 2.django中间件
- 2.1 原始方式
- ==2.2 MiddlewareMixin(建议)==
- 2.3 prcess_request的执行时,是否已执行了路由匹配?
- 2.4 process_view
- process_request和process_view
- 2.5 其他
- 小结
- 3.ORM操作
- 3.1 表结构
- 3.1.1 常见字段和参数
- 3.1.2 表关系
django进阶
- 模板
- 中间件
- ORM操作(pymysql + SQL语句) 内部会转化为sql语句,所以性能会减低,开发效率高
- session和cookie
- 缓存(很多种方式)
内容回顾
-
请求周期
-
路由系统
- 最基本路由关系
- 动态路由(含正则)
- 路由分发不同的app中 + include + 本质 + name + namespace
-
视图
-
类和函数(FBV和CBV)
-
参数 request
- 请求数据
- 自定义数据
-
响应
HttpResponse/JsonResponse/render/redirect return HttpResponse("...") 响应头 obj = HttpResponse("...") obj['xxxxx'] = "值" return obj
-
-
-
其他知识
-
虚拟环境
-
纯净版项目,内置app功能去掉。
-
多app,嵌套到apps目录。
-
pycharm创建django项目 + 虚拟环境
- 最新的django项目
- 低版本(环境+项目+django文件模板)
-
settings配置
django默认settings [先加载] 500 项目目录settings [后加载] 20
-
静态资源
- 静态文件,项目必备【项目根目录,每个app目录下static - app注册顺序】
- 媒体文件,用户上传
-
1.模板
1.1 寻找html模板顺序
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
# 'django.contrib.auth.context_processors.auth',
# 'django.contrib.messages.context_processors.messages',
],
},
},
]
优先去项目根目录 > 每个已注册的app的templates目录找。
如何选择:
- 简单的项目,模板都放在根目录。
- 复杂的项目,模板放在各自的app中,公共部分放在templates目录。
将模板放到各自app中,更有利于组件化
如果不要求组件化,完全可以在根目录的templates分类存放
修改内置app的模板也是同样的套路:
如果想修改django内置app的模板,可以在templates下创建内置app名称的文件夹。
1.2 模板处理的本质
一定是django在将html渲染完成之后(占位符替换后),才将完整的文本信息返回给浏览器的
渲染完成后,生成了字符串,再返回给浏览器
如果将js代码单独放入文件,就不会替换了。:
如果通过导入js文件的形式:浏览器在发现js语句后会再向服务端发送一个请求来单独获取js文件,而此时js文件在static文件夹下,就直接通过static系统直接发送给浏览器了,不需要经过路由系统了。所以此时js文件中的字符串没有被渲染。
以下是浏览器处理 JavaScript 文件的一般流程:
HTML解析:
- 浏览器首先解析 HTML 文档,当遇到
<script>
标签时,会根据标签中的src
属性确定 JavaScript 文件的位置。发送请求获取JS文件:
- 如果
<script>
标签包含src
属性,浏览器会向该 URL 发送一个 HTTP 请求,请求获取 JavaScript 文件。这个 URL 可以是相对路径或绝对路径。静态文件服务:
- 如果 JavaScript 文件位于 Django 的
STATIC_URL
指定的静态文件目录中,Django 的静态文件服务会处理这个请求。这意味着浏览器会直接从静态文件目录获取 JavaScript 文件,而不需要经过 Django 的视图系统。渲染JavaScript代码:
- 浏览器接收到 JavaScript 文件后,会执行其中的代码。如果 JavaScript 文件中包含字符串需要渲染,这些字符串需要在发送请求之前就处理好。
模板渲染:
- 如果 JavaScript 文件中的字符串需要动态渲染(例如,包含变量或模板标签),这些字符串必须在服务器端的模板渲染过程中处理。这意味着 JavaScript 文件应该作为模板的一部分,通过 Django 的模板系统进行渲染。
模板标签:
- 在 Django 模板中,可以通过
{% static %}
模板标签引入静态文件的 URL。这样可以确保 URL 是正确的,并且可以处理模板中的变量。缓存处理:
- 浏览器和服务器可能会对静态文件进行缓存处理,减少重复的请求和提高加载速度。
总结来说,你的理解是正确的:当 JavaScript 文件通过
<script src="...">
标签引入时,浏览器会直接从静态文件服务获取文件,而不是通过 Django 的视图系统。因此,文件中的字符串不会通过 Django 的模板系统进行渲染。如果需要动态渲染这些字符串,需要在服务器端的模板渲染过程中处理。
1.3 常用语法
1.4 内置函数
在django模板语法中提供了内置函数让我们来。
1.5 自定义模板功能
自定义模板函数:
创建templatetags文件夹,并创建一个py文件,并自定义模板函数
filter
多适用于数据处理,1到2个参数,if判断
定义:@register.filter
使用:通过==管道符|==使用:
{{ ‘string’|myfunc }}
simple_tag
多适用于文本展示,参数无限制 & 返回文本信息
定义:@register.simple_tag
使用:通过类似加载static的url的方式:
{% mytag 'arg1' 'arg2' 'arg3' %}
inclusion_tag
多适用于html片段展示,参数无限制 & 返回html片段
定义:@register.inclusion_tag(“app01/xxxx.html”)
返回的是已经渲染完成的html片段
使用:通过类似加载static的url的方式:
{% mytag 'arg1' 'arg2' 'arg3' %}
在模板文件中{% load xx %}导入文件
使用函数
三种方式:
-
filter
- 数据处理,参数:1~2个 - 数据处理,if条件
-
simple_tag
参数无限制 & 返回文本
-
inclusion_tag
参数无限制 & HTML片段
需求来了:根据用户权限不同显示不同的菜单。(inclusion_tag)
1.6 继承和母版
- 如果有extends继承的话,先加载母版,将block替换掉,得到整体的原始文本
- 第二步再进行渲染(替换字符串),所以母版中的占位符字符串也会被替换
母版中至少要包含:
- html:
{% block body %}{% endblock %}
- css:
{% block css %}{% endblock %}
- js:
{% block js %}{% endblock %}
1.7 模板的导入
可以通过include进行片段替换:
{% include “app01/index.html” %}
- 如果有extends继承的话,先加载母版,将block替换掉,得到整体的原始文本
- 再找include,将未渲染的片段替换
- 进行渲染(替换字符串),所以母版中的占位符字符串也会被替换
2.django中间件
- 类
- 定义方法
- 注册
2.1 原始方式
2.2 MiddlewareMixin(建议)
源码实现:
基于反射实现出来可以直接通过继承MiddlewareMixin类来定义中间件,
只需简单的定义
process_request函数
和process_response函数
,而无需再定义__call__
方法。
第一个hasattr是对应请求中间件的,如果定义了process_request,
就在view视图函数执行之前先执行process_request,process_request可以没有或者没有返回值,一般没有
如果response为空(process_request没有返回值),response就是view函数的返回值;
如果response为不为空(process_request有返回值),response就是process_request函数的返回值;
此时,在执行
response=response or self.get_response(request)
时,就不会执行后面的函数了,包括
之后注册的中间件函数,view视图函数
,而是直接去执行该process_request对应的process_response函数,以及已经执行过process_request的中间件对应的process_response函数
。
第二个hasattr是对应响应中间件的,如果定义了process_response,
就在view视图函数执行之后先执行process_response。process_response一定要有返回值。
注意:django1版本。
源码:
-
面向对象
class MyMd(object): def __init__(self....): pass def __call__(self,....): pass django内部默认执行call方法,传入参数。
-
反射
class MyMd(object): def __init__(self....): pass def __call__(self,....): if hasattr(self,'process_request'): response = self.process_request(request) ... django内部默认执行call方法,传入参数。
class MiddlewareMixin: def __init__(self, get_response=None): self.get_response = get_response def __call__(self, request): response = None if hasattr(self, 'process_request'): response = self.process_request(request) response = response or self.get_response(request) if hasattr(self, 'process_response'): response = self.process_response(request, response) return response class MyMd(MiddlewareMixin): def process_request(self,request): ... def process_response(self,request, response): ... django内部默认执行call方法,传入参数。
2.3 prcess_request的执行时,是否已执行了路由匹配?
没有
- 中间件中的request.reslover_match对象为空
- 视图函数中的request.reslover_match对象为路由匹配信息
request.resolver_match
2.4 process_view
注意:process_view是在django中源码中写死了。
在路由匹配成功后,还要再轮流执行中间件中的process_view函数。
如果process_view中有返回值,会跳过view视图函数,从最后一个中间件的process_response函数轮流执行。
process_request和process_view
-
为什么有了process_request还要有process_view呢?
process_request和process_view的区别是:一个没有匹配路由,一个已经匹配路由
process_request(没有匹配路由):可以用做一些所有路由都要做的流程
process_view(已经匹配路由):可以做一些特定的路由要做的流程
2.5 其他
-
process_exception
视图函数异常,process_exception会捕获异常,也可以返回响应
-
process_template_response(了解即可)
只有在视图函数返回TemplateResponse对象时,才会触发中间件中的process_template_response方法,该方法内部时间上会调用render()方法。
所以说process_template_response这种方法实际上就是:
将视图函数直接返回render()分为了两步:
- 返回TemplateResponse对象
- process_template_response函数中调用render()方法
python面向对象中__call__方法
小结
-
定义中间类
-
类方法
- process_request
- process_view
- process_reponse
- process_exception,视图函数出现异常,自定义异常页面。
- process_template_response,视图函数返回
TemplateResponse
对象 or 对象中含有.render方法。
-
应用场景:统一用户验证,解决跨越请求
3.ORM操作
orm,关系对象映射,本质翻译的。
3.1 表结构
实现:创建表、修改表、删除表。
在app中的models.py中按照规则编写类 ===> 表结构。
-
编写类
from django.db import models class UserInfo(models.Model): name = models.CharField(max_length=16) age = models.IntegerField()
-
注册app
INSTALLED_APPS = [ # 'django.contrib.admin', # 'django.contrib.auth', # 'django.contrib.contenttypes', # 'django.contrib.sessions', # 'django.contrib.messages', 'django.contrib.staticfiles', 'apps.app01.apps.App01Config', 'apps.app02.apps.App02Config', ]
-
命令,django根据models中类生成一个
对数据库操作的配置文件
=>migrations
python manage.py makemigrations
-
命令,读取已经注册么给app中的migrations目录将配置文件 -> 转换成:生成表,修改表 SQL -> 连接数据库去运行。
python manage.py migrate
- 那个数据库?
- 数据库账户和密码?
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } }
常见问题:请不要再手动去修改数据的表结构 + 时刻保证 ORM和数据表是对应。
3.1.1 常见字段和参数
-
字段
CharField SmallIntegerField IntegerField positiveIntegerField(无符号) BigIntegerField DateField DateTimeField BooleanField -> 其实数据库不支持真假,根据SmallIntegerField创造出来出来。 0 1 DecimalField -> 精确的小数
-
参数
name = models.CharField(verbose_name="姓名", max_length=16) name = models.CharField(verbose_name="姓名", max_length=16, default="哈哈哈") # 经常查询,速度快(MySQL,https://www.bilibili.com/video/BV15R4y1b7y9) name = models.CharField(verbose_name="姓名", max_length=16, default="哈哈哈", null=True, blank=True, db_index=True) email = models.CharField(verbose_name="姓名", max_length=16, default="哈哈哈", null=True, blank=True, unique=True) # 在数据库存储时只能是:sh、bj (上海、北京一般用于页面显示中文) code = models.CharField(verbose_name="姓名", max_length=16, choices=(("sh", "上海"), ("bj", "北京")),default="sh")
# 不用 max_length=16 count = models.IntegerField(verbose_name="数量", default=1, null=True, blank=True, unique=True) code = models.IntegerField(verbose_name="性别",choices=((1, "男"), (2, "女")),default=1)
register_date = models.DateField(verbose_name="注册时间", auto_now=True)
amount = models.DecimalField(verbose_name="余额", max_digits=10, decimal_places=2)
示例:
from django.db import models
class UserInfo(models.Model):
name = models.CharField(verbose_name="姓名", max_length=16, db_index=True)
age = models.PositiveIntegerField(verbose_name="年龄")
email = models.CharField(verbose_name="邮箱", max_length=128, unique=True)
amount = models.DecimalField(verbose_name="余额", max_digits=10, decimal_places=2, default=0)
register_date = models.DateField(verbose_name="注册时间", auto_now=True)
class Goods(models.Model):
title = models.CharField(verbose_name="标题", max_length=32)
# detail = models.CharField(verbose_name="详细信息", max_length=255)
detail = models.TextField(verbose_name="详细信息")
price = models.PositiveIntegerField(verbose_name="价格")
count = models.PositiveBigIntegerField(verbose_name="库存", default=0)
3.1.2 表关系
注意:ManyToManyField生成的表字段只能id/bid/gid
若有错误与不足请指出,关注DPT一起进步吧!!!