目录
4、3疑问:prcess_request的执行时,是否已执行了路由匹配?
1、静态文件(static)
开发需要:css、js、图片。
- 根目录的 /static/
- 已经app目录下载 /static/ 文件夹下
媒体文件:用户上传的数据(excel/pdf/video)
- 根目录的 /media/
1、静态文件的目录结构
/static/js/XXX
/static/css/xxx
/static/images/xxx
/static/plug/js/XXX/
/static/plug/css/xxx
/static/plug/images/xxx
2、静态文件的配置
INSTALLED_APPS = [
# 'django.contrib.admin',
# 'django.contrib.auth',
# 'django.contrib.contenttypes',
# 'django.contrib.sessions',
# 'django.contrib.messages',
'django.contrib.staticfiles',
"apps.api.apps.ApiConfig",
"apps.web.apps.WebConfig",
]
...
STATIC_URL = '/static/' #在模板中调用static函数时,会自动帮你在路径前补全'/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)#(静态文件首先寻找的路径)
3、很重要:便于理解在模板中调用static函数方法
STATIC_URL = '/static/'
#在模板中调用static函数时,会自动帮你在路径前补全'/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)
#(静态文件首先寻找的路径)
2、2静态文件查找顺序
1、默认先去settings.STATICFILES_DIRS指定的路径找。(公共)
2、- 按注册顺序每个已注册的app中找他static目录,去这个目录中寻找静态文件
3、 - 一般情况下,原则,那个app中的的模板,去哪个那个app中寻找。
4、多app开发:各自app的图片放在各自 /static/app名字/。。。
在开发过程中(模板中)
#1、禁止
<img src="/static/api/1.png">
#2、
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>登录页面</h1>
<a href="/xxx/xxxxx/">调换dao xx</a>
<a href="{% url 'login' %}">跳转</a>
<img src="{% static 'api/1.png' %}">
</body>
</html>
2.3 媒体文件
from django.contrib import admin
from django.urls import path, re_path, include
from django.conf.urls.static import static
from django.conf import settings
from apps.api import views
# 很多功能,很多URL
urlpatterns = [
path('api/', include('apps.api.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
2、模板
2、1模板寻找路径配置
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',
],
},
},
]
1、优先去项目根目录 > 每个已注册的app的templates目录找。
2、如何选择:
-
简单的项目,模板都放在根目录。
-
复杂的项目,模板放在各自的app中,公共部分放在templates目录。
扩展:修改内置app的模板也是同样的套路。
2、2模板处理的本质
渲染完成后,生成了字符串,再返回给浏览器。
先替换在把完整的字符串返回给浏览器
2、3 创建自定义函数文件夹
想要使用自定义模板函数的话需要先创建用于存放函数的文件夹,而在django中对于自定义函数文件夹的名称有严格的要求,即要求存放自定义模板函数的文件夹必须叫templatetags。
- 首先在项目根目录中创建templatetags文件夹
- 创建模板函数py文件,文件名可自定义,笔者这里叫utils.py
templatetags/utils.py
from django import template
from django.utils.safestring import mark_safe
register =template.Library()
自定义函数一般有三种:
1、一种是filter,这个最多只能传递两个参数,可作为if条件使用
- 数据处理,参数:1~2个
- 数据处理,if条件
from django import template
register = template.Library()
@register.simple_tag
def add(a,b):
return a+b
#模板调用方式
<p>{% 2|add:3 %}</p>
#第一个参数 | 函数名:第二个参数
2、一种是simple_tag,这种不会限制参数的个数,但是不能作为IF的条件来使用,参数无限制 & 返回文本返回什么就展示什么
from django import template
register = template.Library()
@register.simple_tag
def mytag1(a,b):
return a+b
#模板调用demo
<p>{% mytag1 %}</p>
<p>{% mytag2 "太卡了" "终于不用听了" %}</p>
3、一种是inclusion_tag,,参数无限制 & HTML片段
@register.inclusion_tag('left_tag.html')
def left_panel(username):
user_obj = models.UserInfo.objects.filter(username=username).first()
blog = user_obj.blog
# 文章分类
category_article_list = models.Category.objects.filter(blog=blog).annotate(num=Count('article')).values('title', 'num')
# 标签分类
tag_article_list = models.Tag.objects.filter(blog=blog).annotate(num=Count('article')).values('title', 'num')
# 时间分类auth_group
time_archive_list = models.Article.objects.filter(user__username=username).extra(
select={'ym': 'DATE_FORMAT(create_time,"%%Y-%%m")'}
).values('ym').annotate(num=Count('nid')).values('ym', 'num')
return {
'username': username,
'category_article_list': category_article_list,
'tag_article_list': tag_article_list,
'time_archive_list': time_archive_list,
}
2、4母板和子版
公共的内容放入母板中(根目录下的template文件下)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="公共css文件">
{% block css %}{% endblock %}
</head>
<body>
<h1>头部</h1>
{% block body %}{% endblock %}
<h1>尾部</h1>
<script src="公共js文件 "></script>
{% block js %}{% endblock %}
</body>
</html>
2、5导入母板
{% extends 'layout.html' %}
{% block css %}
{% endblock %}
{% block body %}
<h1>主页</h1>
{% include "app01/header.html" %}
<p>{{ info }}</p>
{% verbatim %} #不会替换,一般没有意义
<p>{{ info }}</p>
{% endverbatim %}
{% endblock %}
{% block js %}
{% endblock %}
3、将数据库的时间转换为自定义格式
<h2>{{ n9|date:"Y-m-d H:i:s" }}</h2>
4、中间件
4.1中间件配置
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
# 'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
# 'django.contrib.auth.middleware.AuthenticationMiddleware',
# 'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'middlewares.md.MyMd1',
'middlewares.md.MyMd2',
'middlewares.md.MyMd3',
]
1、中间件从上按顺序往下执行
4.2 MiddlewareMixin(建议)
from django.shortcuts import HttpResponse
from django.utils.deprecation import MiddlewareMixin
class MyMd1(MiddlewareMixin):
def process_request(self, reqeust):
print("md1来了")
def process_view(self, request, view_func, view_args, view_kwargs):
# print(request, view_func)
print("view 1")
def process_response(self, request, response):
print('md1走了')
return response
def process_exception(self, request, exception):
# 视图函数,抛出异常
print("异常了", exception)
return HttpResponse("异常了")
def process_template_response(self,request,response):
# 在视图函数中,返回的是TemplateResponse对象; render方法
# response.render()
return response
1、建议继承MiddlewareMixin,不要用原始方法
2、中间件会自动调用__call__方法
class MyMd(object):
def __init__(self....):
pass
def __call__(self,....):
pass
django内部默认执行call方法,传入参数。
默认执行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方法,传入参数。
4、3疑问:prcess_request的执行时,是否已执行了路由匹配?
1、prcess_request的执行时,没有已执行了路由匹配,即:request.resolver_match为none
2、prcess_view的执行时,已执行了路由匹配,即:request.resolver_match为当前路由信息
4、4中间件执行顺序
1、先执行prcess_request,在执行prcess_view
2、prcess_request的执行时,有return时,后面的中间件不执行prcess_request,prcess_response从prcess_request的执行时return的中间件开始执行
3、prcess_view的执行时,有return时,后面的中间件不执行prcess_view,prcess_response从最后一个中间件往前执行(全部执行)
4、5小结
-
定义中间类
-
from django.shortcuts import HttpResponse from django.utils.deprecation import MiddlewareMixin class MyMd1(MiddlewareMixin): def process_request(self, reqeust): print("md1来了") def process_view(self, request, view_func, view_args, view_kwargs): # print(request, view_func) print("view 1") def process_response(self, request, response): print('md1走了') return response def process_exception(self, request, exception): # 视图函数,抛出异常 print("异常了", exception) return HttpResponse("异常了") def process_template_response(self,request,response): # 在视图函数中,返回的是TemplateResponse对象; render方法 # response.render() return response
-
类方法
-
process_request
-
process_view
-
process_reponse
-
process_exception,视图函数出现异常,自定义异常页面。
-
process_template_response,视图函数返回
TemplateResponse
对象 or 对象中含有.render方法。
-
5、中间件执行顺序
1、多个中间件时,process_view是在所有的process_request执行完,在从前往后执行process_view
2、process_request执行过程中return返回时,process_view一个不执行,从当前对象的process_reponse往前执行
3、process_view执行过程中return返回时,从最后一个process_reponse往前执行
4、执行process_view时一定保证process_request都没有问题
5、process_request没有路由信息,process_view有路由信息