- 创建项目
- 在终端创建项目
- pycharm 创建项目
- 默认项目文件
- APP
- 创建 app
- app 的文件结构
- 快速上手
- 启动 django 项目
- 终端启动
- pycharm 启动
- templates 模板
- 静态文件
- 模板语法
- 单个数据
- 传递单个数据给页面变量
- 页面变量接收传递的单个数据
- 列表数据
- 循环语句
- 字典数据
- 嵌套数据
- 判断语句
- 其他一些常用方法
- 请求和响应
- 请求
- 响应
- HttpResponse 对象
- render() 方法
- redirect() 方法
- 数据库操作
- 安装数据库的第三方库
- ORM
- 连接到数据库
- 表操作
- 创建表
- 删除表或字段
- 更改表或字段
- 执行数据库结构变更
- 数据操作
- 新增数据
- 获取(查询)数据
- 删除数据
- 更改数据
- 查询分页
- 母版的使用
- 母版页
- 子页面
- django组件
- Form 表单
- Form 组件
- ModelForm 组件
- 生成表单
- 提交表单
- 填充数据
- 更新数据
- 保存额外数据
- 数据校验
- 简单校验
- 使用正则表达式校验
- 使用校验函数校验
- 自定义校验,返回错误信息
- 信息提示语言
- 后端传递代码到前端
- django 使用 cookie 和 session
- 创建 session 和 cookie 信息
- 获取并检查 session 和 cookie 信息
- session 超时
- 注销 session 信息
- django 的中间件
- 使用中间件
- 自定义中间件
- django 使用 AJAX
- 前端
- 绑定事件方式
- 以 jQuery 方式
- 后端
- 返回 json 数据
- 禁用 csrf 校验检查
- Ajax 结合 ModelForm
- 处理重定位信息
- 处理表单错误信息
Django 框架是一个基于 python 的重量级的 web 开发框架,现今很多大公司大项目都是使用 Django 框架。
可以使用 pip install django 来安装 Django 库
Django官方文档
创建项目可以通过终端和 pycharm 两种方式来创建项目,区别是 pycharm 创建的项目会额外添加了一些模板信息。
在终端创建项目Django 创建项目有点类似于 Scrapy ,在要创建项目的文件夹下,使用终端(命令行)输入命令。django_admin.exe 是在 python 下的 Scripts 下,默认添加到了环境变量中,所以可以直接执行。
django-admin startproject 项目名称
执行完成后,会在当前目录下创建一个项目名称命名的文件夹。这样项目就创建成功了。
pycharm 创建项目在 pycharm 中新建项目时,选择 Django 项目,即可创建 Django 项目了。需要注意的是,使用企业版的 pycharm 。
默认项目文件创建完成的项目目录结构为(learnDjango是项目名称):
learnDjango
│ manage.py
│
└─ learnDjango
asgi.py
settings.py
urls.py
wsgi.py
__init__.py
- manage.py 负责项目的管理,包括启动项目、创建app、数据管理等
- asgi.py 异步接收网络请求
- wsgi.py 同步接收网络请求
- urls.py URL和处理函数的对应关系
- settings.py 项目的配置文件
一个项目下可以有 N 个独立的 app 来处理不同的功能,每个 app 可以拥有独立的、不同的表结构、函数、HTML模板、CSS等。
创建 app终端里,创建好的项目文件夹下,带参数运行 manage.py 即可创建一个新的 app:
python manage.py startapp app名称app 的文件结构
app 的目录结构为(app01是app的名称)
app01
│ admin.py
│ apps.py
│ models.py
│ tests.py
│ views.py
│ __init__.py
│
└─migrations
__init__.py
- migrations 记录 Django 的 model 对数据库进行的变更
- tests.py 进行单元测试
- admin.py django 默认提供的 admin 后台管理
- app.py app的启动
- views.py URL执行的函数(视图函数)
- models.py 操作数据库
当创建了项目和app之后,到应用启动还需要注意以下几点:
- 确保 app 类已经注册
在 app 目录下的 apps.py 中能看到类名称,通常是 app项目名+Config。将此类名称添加到 settings.py 里的 INSTALLED_APPS 列表中即可。需注意的是添加目录名和文件名,例如 ‘app01.apps.App01Config’
- 编写 URL 和视图函数的对应关系
在 urls.py 中编写对应关系。添加到 urlpatterns 列表中,格式为 path('路由路径', 函数名)。例如 path(‘index/’, views.index)。另外注意的是,需要导入 views.py 文件。
- 编写视图函数
在 views.py 中编写视图函数。需注意的是,视图函数默认需有形参 request。例如:
from django.shortcuts import render,HttpResponse
# Create your views here.
def index(request):
return HttpResponse("初学 Django")
启动 django 项目
终端启动
在终端中输入 python manage.py runserver 来启动 django 服务,使用 ctrl + c 来结束服务
pycharm 启动使用 pycharm 建立的 django 项目可以通过默认启动项直接启动,默认快捷键是 shift + F10
templates 模板在视图函数中使用 render() 方法可以返回 html 页面
def index(request): return render(request, 'index.html')
默认情况下 django 会在 app 目录下的 templates 目录下来查找需要使用的 html 页面文件。
需要注意的是,django 并不是在当前 app 的 templates 目录下寻找,而是根据 app 的注册顺序,查找相应 app 目录下的 templates 目录下查找 html 文件。
另外,可以在项目 settings.py 文件中的 TEMPLATES 字段下的 ‘DIRS’ 添加参数 [os.path.join(BASE_DIR, 'templates')] ,则优先在项目根目录下的 templates 目录下查找 html 文件。
静态文件在开发过程中,一般将图片、CSS、js 等作为静态文件处理。django 会将静态文件存放在 app 目录下的 static 文件夹下。html 指向静态文件时使用相对路径,例如 src="/static/1.png"。所以一般 static 目录下会创建 img、js、css、plugins 等文件夹存放相应的静态文件。
不过 django 推荐这样使用静态资源:
{% load static %}
如果需要更改 static 目录,则在 settings.py 文件里的 STATIC_URL 里更改。
模板语法模板语法本质上是写 HTML 时写一些占位符,由数据对占位符进行替换和处理。
django 的模板语法是包含在 { } 中的。
单个数据 传递单个数据给页面变量使用 render() 方法时,可以添加一个字典参数,将需要传递到 html 中变量的变量名和值写入:
def index(request):
text = '初学 Django'
return render(request, 'index.html', {"n1": text})
页面变量接收传递的单个数据
在页面中使用 {{ 变量名 }} 来接送 render() 方法传递的数据。
列表数据{{ n1 }}
列表数据的传递和单个数据是一样的。区别在于接收时,索引不再使用方括号,而是使用点:
def index(request):
text=["Python", "C", "Java", "Basic"]
return render(request, 'index.html', {"n1": text})
循环语句计算机编程语言有 {{ n1.0 }},{{ n1.1 }},{{ n1.2 }},{{ n1.3 }} 等
循环的语法如下:
{% for item in n1 %}
{{ item }}
{% endfor %}
字典数据
字典数据的传递是一样的。接收时,使用 变量名.键 来获取字典数据。
def index(request):
text ={"y1": "Python", "y2": "C", "y3": "Java", "y4": "Basic"}
return render(request, 'index.html', {"n1": text})
第一种语言是 {{ n1.y1 }},第二种语言是 {{ n1.y2 }},第三种语言是 {{ n1.y3 }},第四种语言是 {{ n1.y4 }}
字典也可以使用循环
{% for k, v in n1.items %}
对于嵌套的数据,例如列表里嵌套的字典,在接收时也可以使用嵌套的方式获取。类似于 python ,只是方括号改成了小数点。
判断语句判断语句语法如下:
{% if text == "Django老手" %}
高手高手高高手
{% elif text == "初学 Django" %}
菜鸟一个
{% else %}
无法识别
{% endif %}
其他一些常用方法
- 日期格式,使用管道符设置格式
{{ 日期数据 | date:“Y-m-d H:i:s” }}
请求和响应 请求{{ bio | truncatewords:“30” }}
{{ my_list | first | upper }}
{{ name | lower }}
视图函数中有一个默认形参 request,它是一个对象,封装了用户发送过来的所有请求数据。 request 对象的常用属性和方法有:
- request.method :请求类型
if request.method == "GET": return render(request, "login.html")
- request.GET :通过URL传递的参数
- request.POST :通过请求体提交的数据
username = request.POST.get("user")
password = request.POST.get("pwd")
响应
HttpResponse 对象
使用 HttpResponse 对象可以直接返回响应包,例如 HttpResponse(‘String’) 的响应包返回内容就是字符串。
render() 方法使用 render() 方法通常返回一个 html 页面,也可以使用此方法向页面中传递数据。
redirect() 方法redirect() 方法会重定向到另一个 url ,使用方法为:return redirect("https://www.baidu.com")
数据库操作Django 开发操作数据库更简单,其内部提供了 ORM 框架,可以轻松的访问数据库。Django 官方支持 PostgreSQL、MariaDB、MySQL、Oracle、SQLite,还支持 MS SQL Server 等提供的后端。
安装数据库的第三方库django 数据库是基于其他的第三方库,所以需要先安装。 这里使用 MySQL 数据库。因为 django 对 pymysql 的支持不是很好,据说有错误,所以使用 mysqlclient 库。pip install mysqlclient
ORMORM 是 django 操作数据库的模块,可以创建、修改、删除数据库中的表(无法创建、删除数据库),还可以操作表中的数据。
连接到数据库ORM 连接数据库需要在 setting.py 中对 DATABASES 列表字段进行设置:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # 数据库引擎
'NAME': 'mytest', # 数据库名
'USER': 'root', # 访问数据库用户名
'PASSWORD': '123456', # 访问数据库用户的密码
'HOST': 'localhost', # 数据库主机
'PORT': 3306 # 访问数据库的端口
}
}
表操作
创建表
django 对于表的操作是在 models.py 文件中进行。
在此文件中,创建一个类,继承 models.Model 类,即可创建表。然后在内的成员中定义表结构。
class UserInfo(models.Model):
name = models.CharField(max_length=16, verbose_name='姓名')
password = models.CharField(max_length=64, verbose_name='密码')
age = models.IntegerField(verbose_name='年龄')
account = models.DecimalField(verbose_name='工资账户金额', max_digits=10, decimal_places=2, default=0) # 精准小数,最大位数10位,小数位2位,默认值为0
create_time = models.DateTimeField(verbose_name='入职时间')
depart = models.ForeignKey(to='Department', to_field='id', on_delete=models.CASCADE) # 外键,关联到 Department 表的 id 字段,级联删除
gender_choices = ((1, '男'), (2, '女'))
gender = models.SmallIntegerField(verbose_name='性别', choices=gender_choices)
数据库中,表名称为app名称 + 下划线 + 小写类名。字段名称就是定义的成员变量,另外会自动添加一个名称为 id 的 bigint 型的自增字段作为主键。
常用的类型有:
- CharField : varchar 类型
- IntegerField : int 类型
- DecimalField : decimal 类型(精准小数)
- DateTimeField :日期时间类型
- ForeignKey :外键类型
常用的参数有:
- max_length :最大长度(字符串类型使用)
- verbose_name :备注名称
- default :默认值
- null :是否可以为空
- blank :同 null,通常一起使用
- max_digits :数值最大位数
- decimal_places :小数部分位数
- to :关联表(外键)
- to_field :关联列(外键)
- on_delete :主键删除时处理方式(外键),可以使用值有 models.CASCADE (级联删除) 和 models.SET_NULL (置空)
- choices :django 的选择值约束
# choices 选择约束
gender_choices = ((1, '男'), (2, '女'))
gender = models.SmallIntegerField(verbose_name='性别', choices=gender_choices)
删除表或字段
只需要在 models.py 文件中,将需要删除的表相对的类删除(或注释),即可删除表。同理删除字段就是在类定义中将相应字段定义的成员删除。
更改表或字段更改表或字段和删除表或字段类似,更改 models.py 文件中相应的类或类的成员即可。需要注意的是更改时数据库对数据的约束条件。例如没有设置可为空或具有默认值的字段,添加时要输入默认值等。
执行数据库结构变更在终端执行命令
python manage.py makemigrations
就会读取并处理 models.py,如果第一次则会在 migrations 文件夹下建立索引为 1 的初始化文件 initial.py 。之后每次执行此命令会根据当时的 models.py 和 migrations 下的历史文件,对数据库表进行比较,创建结构变更记录文件。
然后在终端执行
python manage.py migrate
就会根据 migratrons 下最后的变更文件,对数据库相应表的结构进行变动。
另外需要注意的是,需要在 setting.py 文件中注册相应的 app。
数据操作 新增数据在实际使用中,会在视图函数中进行数据操作,所以在 views.py 中需要引入 models.py 文件。
在视图函数中,可以使用表相应类的 create 方法添加数据
from app01 import models # 添加数据,使用 models.表相应的类名称.objects.create(字段=值,字段=值...) models.Department.objects.create(title='销售部') models.UserInfo.objects.create(name='张三', password='123456', age=19)获取(查询)数据
可以使用 all 方法获取所有数据,得到的是 QuarySet 类型的对象,可以当成数据列表,列表中的每个元素都是一个数据对象可以使用 对象.字段 的方式获取数据。
data_list = models.UserInfo.objects.all() for data in data_list: print(data.id,data.name,data.password,data.age)
也可以使用 filter 方法进行条件筛选,但是筛选出来的数据哪怕只有一条,获取的也是 QuarySet 对象。不过可以使用 first 方法从 QuarySet 中获取第一条数据。
data = models.UserInfo.objects.filter(id=1).first()
对于查询条件,除了等于外还有
| 示例 | 说明 |
|---|---|
| id=12 | 数值字段id的值等于12 |
| id__gt=12 | 数值字段id的值大于12 |
| id__gte=12 | 数值字段id的值大于等于12 |
| id__lt=12 | 数值字段id的值小于12 |
| id__lte=12 | 数值字段id的值小于等于12 |
| name__startswith=“张” | 字符串字段name以 “张” 开始 |
| name__endswith=“三” | 字符串字段name以 “三” 结尾 |
| name__contains=“老” | 字符串字段name包含了字符串 “老” |
另外可以使用 exclude 方法来排除筛选条件
data = models.UserInfo.objects.filter(age=19).exclude(id=2).first()
可以使用 count 方法来返回查询记录总数
num = models.UserInfo.objects.filter(age__gt=19).count()删除数据
找到了需要处理的数据后,可以使用 delete 方法进行删除
models.Department.objects.all().delete() models.UserInfo.objects.filter(id=3).delete()更改数据
类似于删除数据,可以使用 update 方法对数据进行更新
models.Department.objects.all().update(password=999) # 将所有数据的 password 字段值改为 999 models.UserInfo.objests.filter(id=3).update(name='张三',password='5445',age=20)查询分页
django 可以控制返回查询记录的起始索引和结束索引,有点类似于切片。即,使用 [ 起始记录索引号 : 结束记录索引号 ] 的方式,并且也遵循左闭右开的原则。
models.UserInfo.objects.all()[0:10] # 返回查询结果索引为 0 - 9 的记录 models.UserInfo.objects.filter(age__gte=22)[10:20] # 返回查询结果索引为 10 - 19 的记录
这样就可以进行分页了。起始记录索引号的值为 (页码 - 1) * 每页大小 , 结束记录索引号的值为 页码 * 每页大小。
母版的使用有些页面内容可以作为母版使用,在母版页面中填充子页面,可以提高代码复用,减少工作量。
母版页在母版页中,需要更改内容(放置子页面)的地方,使用 block 进行标记,即制作好了母版页。
{% load static %}
部门列表
{#导航条#}
{#内容#}
{% block content %}{% endblock %}
子页面
在子页面的第一行,写入要继承的母版页,然后将需要填充到母版页的代码同样使用 block 标记即可。
{% extends 'layout.html' %}
{% block content %}
{#内容#}
...
{% endblock %}
django组件
Form 表单
form 表单的用法和 flask 等其他方法大致一样,不一样的地方在于 django 自带 csrf_token 校验。在视图函数获取表单数据时,会比对 csrf_token 的值,所以在 html 中的form 表单内部需要添加 {% csrf_token %} 用来生成随机值以进行比较。但是使用 form 表单会有很多问题,例如数据校验、错误提示、页面字段需要重写、关联表的数据呈现需要手动写入等等。所以在开发时通常使用 django 提供的组件来实现。
Form 组件django 提供的 form 组件能够自动对数据进行校验,能够提供错误提示,能够自动生成字段。
使用 form 组件需要在 views.py 中创建一个继承自forms.Form的类,用来处理 form 的内容。
from django import forms class MyForm(forms.Form): # 定义 form 的字段,并使用插件 user = form.CharField(widget=forms.Input,label='用户名',required=True) pwd = form.CharField(widget=forms.Input,label='密码',required=True) email = form.CharField(widget=forms.Input)
然后在视图函数中实例化此类,并传递给前端页面
def index(request):
form = MyForm()
return render(request, 'index.html', {'form': form})
然后前端页面使用 form 对象创建表单,而不是使用 等标签创建。form 对象会自动生成插件所标识的 html 标签。
field.label 可以获取字段的 verbose_name 名称,如果没有定义则取字段名称。
ModelForm 组件使用 form 组件时,所有字段还是需要手动写一遍(在 views.py 定义的 form 类中),如果觉得麻烦,django 提供了另一个组件: ModelForm 组件。
生成表单使用 ModelForm 组件需要在 views.py 中创建一个继承自ModelForm的类,用来处理 form 的内容。
from django import forms class MyForm(forms.ModelForm): # 也可以使用自定义字段 # xx = form.CharField() # 需要嵌套类 Meta class Meta: model = UserInfo # UserInfo 是 models.py 中定义的相应数据表的类 fields = ["name", "password", "age"] # 确定要操作的字段 # fields = "__all__" # 使用全部字段 # exclude = ["password"] # 排除特定字段,选择其他字段 # 使用自定义字段 # fields = ['name', 'password', 'age', 'xx']
传递数据和前端使用上则和 Form 组件类似
自动生成的标签会丢失样式,所以实际使用中,会在定义要操作的字段时,定义字段的插件及属性,在插件属性中可以添加样式。
from django import forms
class MyForm(forms.ModelForm):
class Meta:
model = UserInfo
fields = ["name", "password", "age"]
widgets = {
'name': forms.TextInput(attrs={'class': 'form-control'}), # 定义字段使用的插件
'password': forms.TextInput(attrs={'class': 'form-control'}) # 插件的参数中可以添加属性,将样式添加到这里
}
不过这样也字段多的时候也会比较麻烦。通常项目中会在 MyForm 初始化时,通过遍历字段给各字段添加属性的方式添加样式
from django import forms
class MyForm(forms.ModelForm):
class Meta:
model = UserInfo
fields = ["name", "password", "age"]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for name, field in self.fields.items():
# 设置属性
if field.widget.attrs: # 如果字段中有属性,保留原属性
field.widget.attrs['class'] = 'form-control'
field.widget.attrs['placeholder'] = '请输入' + field.label
else:
field.widget.attrs = {'class': 'form-control', 'placeholder': '请输入' + field.label}
提交表单
ModelForm 组件的表单时,可以将数据返回定义的类来进行校验等操作
form = MyForm(data=request.POST) # 创建对象,将提交的表单数据作为参数
if form.is_valid(): # 使用 is_valid 方法对数据进行有效性校验,如果有效返回 True
print(form.cleaned_data) # 整理数据成一个字典
form.save() # 保存数据
else:
# 如果校验失败,此时错误信息会保存在 form 里,可以将其返回页面,在页面中接收
return render(request, 'user_add_ModelForm.html', {'form': form})
{% for field in form %}
{{ field }}
{{ field.errors.0 }}
{% endfor %}
填充数据
如果需要在表单中填充数据,例如编辑的时候会有默认数据,只需要创建 form 对象时将数据库数据作为参数传给类的 instance 参数即可,其他的完全同生成表单
def user_edit(request, nid):
"""编辑用户"""
if request.method == "GET":
row_obj = models.UserInfo.objects.filter(id=nid).first()
form = MyForm(instance=row_obj)
return render(request, 'user_edit.html', {'form': form})
更新数据
在提交表单时,使用 form.save() 方法可以添加数据到数据库,但是更新原有数据时必须告诉 form 操作的是哪条数据
row_obj = models.UserInfo.objects.filter(id=nid).first()
form = UserModelForm(data=request.POST,instance=row_obj)
if form.is_valid(): # 检测数据有效性
form.save() # 保存进数据库
return redirect('/user/list/')
else:
# 校验失败,显示错误信息
return render(request, 'user_add_ModelForm.html', {'form': form})
保存额外数据
使用 form.save() 方法保存表单数据到数据库时,实际上保存的是用户提交的表单中的数据。如果有一些其他的数据不在用户提交的保单中,则可以手动添加数据到字段,然后保存
form = UserModelForm(data=request.POST)
if form.is_valid(): # 检测数据有效性
# 使用 form.instance.字段名 = 值 来手动添加数据,然后保存到数据库
form.instance.position = '新入职员工'
form.save() # 保存进数据库
return redirect('/user/list/')
else:
# 校验失败,显示错误信息
return render(request, 'user_add_ModelForm.html', {'form': form})
数据校验
简单校验
is_valid 方法默认进行空值检测,如果需要更多校验方式,例如字符位数等,需要自定义字段
from django import forms class MyForm(forms.ModelForm): name = forms.Charfield(min_length=3,label="用户名") # 此字段最小长度为3个字符 # name = forms.Charfield(disabled=True,label="用户名") # 不可用模式,但是提交表单时认为是空 password = forms.Charfield(label='密码',required=True) # 必填校验 class Meta: model = models.UserInfo fields = ['name', 'password', 'age']使用正则表达式校验
在自定义字段时,可以添加参数 validators,使用正则表达式 RegexValidator 类进行校验自定义的字段。
from django.core.validators import RegexValidator
class PrettyNumForm(forms.ModelForm):
mobile = forms.CharField(
label='手机靓号',
validators=[RegexValidator(r'^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])d{8}$','手机号格式错误')] # 参数2表示校验失败显示内容
)
class Meta:
model = models.PrettyNum
# fields = "__all__" # 使用所有字段
# exclude = ['level'] # 排除某个字段,取其他的字段
fields = ['mobile','price','level','status']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for name, field in self.fields.items():
if type(field.widget) == django.forms.widgets.TextInput or type(field.widget) == django.forms.widgets.NumberInput:
field.widget.attrs = {'class': 'form-control', 'placeholder': '请输入' + field.label}
else:
field.widget.attrs = {'class': 'form-control'}
使用校验函数校验
可以在类定义中使用 clean_字段名 方法,将相应的字段数据传入并进行校验
def clean_mobile(self): # 校验 mobile 字段
from django.core.exceptions import ValidationError
txt_mobile = self.cleaned_data['mobile'] # 获取 mobile 字段的数据
if len(txt_mobile) != 11: # 进行检验
raise ValidationError("格式错误") # 没通过检验,抛出一个错误
else:
return txt_mobile # 通过检验,返回值
自定义校验,返回错误信息
可以通过 form.cleaned_data 获取返回的 form 数据字典,所以可以通过 form.cleaned_data[key] 来获取需要的表单数据,来自定义一些数据校验方式。也可以使用 form.cleaned_data.pop(key) 的方式来获取特定键的值,区别在于使用 pop 方法为弹出数据。
如果自定义校验,或者进行数据核对(例如比较数据库中的信息),则可以主动添加错误信息并返回。
form = UserModelForm(data=request.POST)
if form.is_valid(): # 检测数据有效性
if models.UserInfo.objects.filter(name=form.cleaned_data['username'], password=form.cleaned_data['password']).exists():
# 登录成功,跳转页面
return redirect('/user/list/')
else:
# 用户名和密码对不上
form.add_error('password', '用户名或密码错误') # 主动添加错误信息给 password 字段
# 校验失败,显示错误信息
return render(request, 'user_add_ModelForm.html', {'form': form})
信息提示语言
通过实例测试可以知道,返回的错误信息是英文的,这是因为 django 在设置上是使用英文 en-us ,可以在 setting.py 中的 LANGUAGE_CODE 设置成中文 zh-hans
后端传递代码到前端有时候,在前端不好确定的代码,可以通过后端生成,然后传递给前端使用。这里以翻页的手动代码进行举例:
from django.utils.safestring import mark_safe # 将后端字符串标记为安全,可以传递到前端做为前端的 HTML 代码使用
# 前端的翻页页码
page_list = []
# 计算出当前页的前三后三页
if page >= 5: # 需要首页
ele = f'如果不使用 mark_safe 标记,传到前端的数据会以字符串形式呈现。标记后则前端认为字符串是就是前端代码。
django 使用 cookie 和 session 创建 session 和 cookie 信息在 django 中,使用 request.session[key] = value 能够记录 session 的信息,同时会自动生成验证 session_id 返回到用户浏览器 cookie 中,并且将 session_id 和验证字符串都存储到数据库的 django_session 表中,以便下次使用时自动验证。
获取并检查 session 和 cookie 信息如果是已经记录 session 信息的用户再次访问,则请求信息的 cookie 中会有 session_id 。django 会从数据库中查询是否存在此 session_id,如果存在则能够获取设置的 session[key] 的 value ,如果不存在则不能够获取。所以使用 request.session.get(key) 来获取设置数据就能够自动检查 session 信息。
session 超时可以使用 request.session.set_expiry(sec) 来设置 session 的超时时间,sec 单位为秒。
注销 session 信息使用 request.session.clear() 方法可以清除 session 信息,即进行注销。
django 的中间件django 收到一个请求后,会经过一系列的中间件后达到视图函数,经过视图函数处理后,再经过这些中间件后将数据返回给用户浏览器。
中间件处理请求的方法是 process_request,处理响应的方法是 process_response。如果请求在通过中间件时, process_request 没有返回值(或返回值为 None),则会继续交给下一步处理;如果有返回值(返回值是 HttpResponse、render、redirect),则会禁止请求往下进行,而将返回值交给本类的 process_response 方法返回请求,直接返回给客户端,所以可以将一些放在视图函数之前或之后的行为写在中间件中。
中间件的处理顺序按照在 settings.py 中注册的顺序,请求是顺序处理,响应是逆序处理。
使用中间件django 使用的中间件可以在 settings.py 中的 MIDDLEWARE 字段定义。
自定义中间件所有自定义的中间件(类)需继承 django.utils.deprecation.MiddlewareMixin 类。并且要在 settings.py 中添加注册
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import redirect
class AuthMiddleware(MiddlewareMixin):
"""访问验证中间件"""
def process_request(self,request):
# 如果请求访问 login 页面则不进行检测
if request.path_info == '/login/': # request.path_info 能获取请求URL
return
# 1. 读取当前访问用户的 session 信息,如果能读到,说明已经登录过
username = request.sesssion.get('username')
if username:
return
# 2. 如果没有登录过,
else:
return redirect('/login/')
def process_response(self,request,response):
return response
django 使用 AJAX
django 项目中也可以使用 ajax 技术
前端前端和其他 web 框架一样,需要注意的是,django 接收 POST 请求时,需要 csrf_token 进行验证,而在 ajax 中获取 csrf_token 比较麻烦。所以通常会在后端免除 csrf_token 验证。
绑定事件方式{% extends 'layout.html' %}
{% block content %}
任务管理
{% endblock %}
{% block js %}
{% endblock %}
以 jQuery 方式
{% extends 'layout.html' %}
{% block content %}
任务管理
{% endblock %}
{% block js %}
{% endblock %}
后端
后端部分只要将响应请求 url 绑定视图函数,则可以在视图函数中进行处理
def task_ajax(request):
"""测试ajax"""
return HttpResponse('成功')
返回 json 数据
可以使用 json 的 dumps 方法将字典转为 json 并返回
import json
def task_ajax(request):
res_dict = {'res':'ok', 'data':{'k1': 'v1', 'k2': 'v2'}}
res_dict = json.dumps(res_dict)
return HttpResponse(res_dict)
也可以直接使用 JsonResponse 返回数据
from django.http import JsonResponse
def task_ajax(request):
res_dict = {'res':'ok', 'data':{'k1': 'v1', 'k2': 'v2'}}
return JsonResponse(res_dict)
禁用 csrf 校验检查
前端发送 post 请求时如果不加载 csrf_token,则后端需要禁用 csrf 校验检查
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def task_ajax(request):
return HttpResponse('成功')
Ajax 结合 ModelForm
Ajax 结合 ModelForm 在前端实际上几乎没有改变,要注意的也就是按钮绑定 Ajax 函数和不用 csrf_token。
在后端,ModelForm 其实接收到的数据也是 form 的字典格式,包含校验、保存等处理方式没有变化,只是在返回值时有了变化。
处理重定位信息因为 Ajax 是接收处理数据,所以后端返回 重定位 信息是无法跳转的。如果希望跳转,则需要返回一个 json ,ajax 收到了这个特定的 json 数据后使用 js 进行页面跳转。
处理表单错误信息另外返回 ModelForm 错误信息时,form.errors 获取的是一个字典,可以整理成 json 格式返回给 ajax 处理。



