初识Django-前后端不分离(二)
上下文管理器
作用:每个view里面都需要用到的操作也就是公共的东西,就可以放到你自己定义的上下文管理器中查,这样在views.py里就不用重复写了
执行的顺序:每一个视图请求完后都会再请求一次上下文管理器
如何使用上下文管理器:
- 首先定义一个上下文管理器:process_context.py
- 在上下文管理器中定义的函数,函数必须有一个参数,是request
- 这个函数要返回一个字典(这里额外介绍一个函数locals(),locals作用是把当前这个函数里所有的局部变量变成一个字典。下方有例子)
- 在这里创建的函数,需要在settings.py里的TEMPLATES->OPTIONS->context_processors下配置,每一个函数都需要配置一下。
#上下文管理器process_context.py from . import models def category_process(request): print('category_process.....') catagories = models.Category.objects.filter(is_delete=False) return {'nav':catagories} def site_process(request): site_name='塔塔的博客' desc='今天是周天,明天是周一' return locals() #locals作用是把当前这个函数里所有的局部变量变成一个字典。这一行等同于下面一行, # return {'site_name': site_name,'desc':desc}
settings.py TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')] , 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'user.process_context.category_process', #这里配置创建的函数 'user.process_context.site_process' ], }, }, ]
模版继承
不同的html文件中也会有一些公用的内容,我们同样可以把他们抽离出来,单独放到一个html文件中,我们把这种叫做模版继承。
如何使用模版继承
- 首先创建一个base.html,用于存放公用的内容
- base.html中需要变化的内容用block标记。格式如下(注意css和js有时候也是需要变得,所以在base.html中一般也会预留出css和js的口)
{% block content %} 中间是变化的内容 {% endblock %} #content这是用来标识变化的内容的,是可变的,如果是css则替换成css即可
3. 公共的内容抽离出去里后,原有的html中需要指定继承哪个公共的html里的内容(这里就是继承base.html)。
{% extends 'base.html' %}
4. 原有的html中还要指定可变的内容是什么,用{% block content%} 中间是可变的内容 {% endblock %}
分页
需导入django自带的分页的类:from django.core.paginator import Paginator
后端分页相关知识:
from django.core.paginator import Paginator l=range(1,51) page_obj=Paginator(l,10) #10个分一页 # page_obj = Paginator(Article.objects.all(),2) #从数据库查文章表数据,2个一页 print(list(page_obj.page(1))) print(page_obj.page(1)) #取某一页的数据,显示的结果是这种<Page 1 of 2>,表示一共多少页现在在哪一页 print(list(page_obj.page(1))) #转成list就能展示出取某一页的数据了 print(page_obj.count) #总共多少条 print(page_obj.num_pages) #总共分了多少页 print(page_obj.page_range) #分页的范围 cur_page = page_obj.page(1) #当前在那一页 print(cur_page.has_previous()) #判断是否有上一页,要先指定当前在那一页 # print(cur_page.previous_page_number()) #取上一页的分页号码 print(cur_page.has_next())#判断是否有下一页 print(cur_page.next_page_number()) #取下一页的分页号 print(cur_page.has_other_pages()) #判断是否有其他页 print(cur_page.paginator) #相当于page_obj
前端实现代码: {% if articles.has_other_pages %} <div class="pagelist"> {% if articles.has_previous %} <a href="/index?page={{ articles.previous_page_number }}&limit=10"><b>上一页</b></a> {% endif %} {% for page_num in articles.paginator.page_range %} <a href="/index?page={{ page_num }}&limit=10" >{{ page_num }}</a> {% endfor %} {% if articles.has_next %} <a href="/index?page={{ articles.next_page_number }}&limit=10">下一页</a> {% endif %} </div> {% endif %}
丰富Django管理后台
- 美化Django管理后台样式
- 首先安装pip install simpleui
- 其次在settings.py->INSTALLED_APPS下添加'simpleui'
- 丰富Django管理后台某数据库页面操作项
在子项目下的admin.py文件中进行配置
from django.contrib import admin # Register your models here. from . import models #配置如下class类,可以丰富页面的操作项,对应下方操作页面的admin.site.register里也要增加类名 class ArticleAdmin(admin.ModelAdmin): list_display = ['title', 'category', 'create_time', 'update_time'] #显示哪些字段 search_fields = ['title'] #指定按哪写字段搜索,不要写外键的字段 list_filter = ['category','is_delete'] #根据哪个字段筛选 list_per_page = 10 #每页显示多少条 admin.site.register(models.Article,ArticleAdmin) #这里增加ArticleAdmin
前后端不分离的流程
urls.py里面匹配url,找到对应的url里面的函数,读取函数里的内容将数据和html交给render,render在templates里找对应的html,找到后读取该html里的内容映射到页面
前后端分离
跨域问题:安装pip install django-cors-headers 后即允许跨域
有一些文章显示内容太多会截断用....展示,这需要如何操作呢?
- 自定义tag标签
在子项目下创建一个templatetags文件夹(注:文件夹名必须固定叫templatetags,文件夹下要有个__init__.py文件),在templatetags文件夹中建一个my_tag.py的文件,在这里自定义我们需要的函数,前端可以直接调用 (注:my_tag.py中的register变量名是固定不可变的)
my_tag.py from django import template register=template.Library() # register固定的变量名,不能改 @register.filter #filter最多有2个参数,前端使用时首先{% load my_tag %},其次在用的地方加上|+函数名,如果是两个参数需要用到:,如{{ article.desc | test:10}} def abc(s,length=10): #判断字符串大于10就截断以...显示 if len(s)>length: s=s[:11]+'.....' return s @register.simple_tag #simple_tag 不限制参数,如果参数很多用这个 def abc2(s,length=10): if len(s)>length: s = s[:11]+'....' return s
2. 在前端调用我们自定义的函数
第一步:在对应的html中load我们创建的python文件my_tag {% load my_tag %} 第二步:在具体的内容处引用 第一种自定义filter最多有2个参数 一个参数的用法 <p>{{ article.desc | abc}}</p> 二个参数的用法 <p>{{ article.desc | abc:10}}</p> 第二种自定义simple_tag不限制传参个数用法 <p>{% abc2 article.desc 10 %}</p>
Django自带的过滤器
{% load my_tags %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link href="/static/style.css" rel="stylesheet"> </head> <body> 欢迎《{{name}}》登录,今天是 === {{time}} === {{ stus.0 }} <br> {{ stus |length }} <br> {{ stus |slice:"0:2" }} <br> {{ stus |join:"-" }} <br> {{ name |default:"admin" }} <br> {{ cur_time |date:"Y-m-d H:i:s" }} <br> {{ h1_str |safe }} {# #xss注入,加safe表示安全#} <br> {{ h1_str }} <br> {{ words | truncatechars:20 }} <br> {{ age | add:2 }} <br> {{ name | add:"先生" }} <br> {{ english_name | upper }} <br> {{ english_name | lower }} <br> {{ article_content|mingan }} <br> {{ article_content|mingan2:"金正恩" }} <br> {% mingan3 say "213" "sb" "傻x" %} {# <ul>#} {# {% for stu in stus %}#} {# <li>{{stu}}</li>#} {# {% endfor%}#} {# </ul>#} </body> </html>
CSRF TOKEN
csrf token的作用:为了防止重复提交的。
django默认post请求都需要加csrf token,如果不加请求不成功,报禁止访问(403) CSRF验证失败,请求被中断
两种解决方法:
1. 在settings.py->MIDDLEWARE里把csrf的校验注释掉(注释掉就会有重复提交的风险)
2. 如果不注释掉,就在html的form表单中写{% csrf_token %}
cvb和fvb
函数写法的方式是fvb ,在urls.py里配置链接时是:path('add_article/', add_article),
类写法的方式是cvb,cvb在配置url时,需导入ArticleView,写法:path('add_article/', ArticleView.as_view()),
#fvb :用函数是需要判断是get还是post请求 def add_article(request): if request.method=='GET': categories = Category.objects.all() return render(request,'form.html',locals()) else: title = request.POST.get('title') desc = request.POST.get('desc') category = request.POST.get('category') content = request.POST.get('content') article = Article(title=title,desc=desc,category_id=category,content=content) article.save() return HttpResponseRedirect('/index') # HttpResponseRedirect表示重定向 #cvb :不需要判断直接定义2个方法,一个get一个post即可 #导入View from django.views import View class ArticleView(View): def get(self,request): print('get请求...') categories = Category.objects.all() return render(request, 'form.html', locals()) def post(self,request): print('post请求...') title = request.POST.get('title') desc = request.POST.get('desc') category = request.POST.get('category') content = request.POST.get('content') article = Article(title=title, desc=desc, category_id=category, content=content) article.save() return HttpResponseRedirect('/index') # 重定向
嗯。。