Django2开发必备技术点总结(一)
主要基于Django2.0.1为大家总结其中的核心技术,如果全部掌握则具备开发Web项目的能力。
为了更好的学习其知识点,我已在B站上传相关的视频:https://space.bilibili.com/485885102/channel/detail?cid=111581。如果在学习的过程中遇到问题,可以以QQ(610039018)方式沟通。
一、 Django入门
1.1 基本概念
1.2 创建环境与app项目
安装依赖包
pip install django==2.0.1 -i https://mirrors.aliyun.com/pypi/simple
【注意】如果Python版本(3.7.4+)很高时,SQLite3版本同样很高,则django版本建议使用django==2.1.5+;因为,admin.site 站点管理时,会报auth_user_old表不存在的错误。
进入"终端" CMD命令, 通过 django-admin 命令创建django项目。
django-admin startproject helloDjango
通过django-admin命令创建app应用
django-admin startapp mainapp
在一个Django项目中,存在很多的app应用(模块), 创建好的app需要注册到主工程中(settings.py)
Django中常用的命令包括:
- django-admin startproject 创建django项目
- django-admin startapp 创建django的app模块
- python manage.py makemigrations 基于settings中配置的DATABASE数据default方案生成迁移脚本
- python manage.py migrate 开始迁移
- python manage.py createsuperuser 创建admin站点的超级用户
- python manage.py runserver 启动django服务,默认端口是8000, host为127.0.0.1
1.3 django项目结构
项目结构如下:
helloDjango
|--- helloDjango 主工程目录
|---- settings.py # 设置文件, 数据库连接、app注册、中间件及模板配置
|---- urls.py # 总路由
|---- wsgi.py # Django实现wsgi的脚本
|---- __init__.py
|--- mainapp 应用模块(主)
|---- __init__.py
|---- admin.py # 后台管理配置脚本
|---- models.py # 数据模型类声明所在脚本
|---- views.py # 声明当前应用的视图处理函数或类
|---- urls.py # 自已增加的当前应用模块的子路由
|---- tests.py # 当前应用模块的单元测试类
|---- apps.py # 声明当前应用的基本信息
|--- manage.py WEB应用的启动脚本, 项目工程的入口
1.4 Django请求流程
1. 到urls分发器 (总urls.py -> 子路由)
2. urls分发器根据路由规则(正则)分发到views
3. views去调用Model,交互数据
4. views将数据渲染到模板中
5. 模板呈现给用户
二、 数据库连接与ORM模型
2.1 数据库连接配置
默认是sqlite3数据库, 在使用ORM模型之前,需要先生成迁移文件,再执行迁移命令,在数据库中生成这些模型对应的表。
- 先生成迁移文件
python manage.py makemigrations
- 开始迁移(生成表、 修改表、删除表)
python manage.py migrate
注意: 一旦生成了迁移文件并且迁移成功之后,不要删除迁移文件。
2.2 初步使用ORM模型
在app模块中的models.py 定义一个用户(客户)模型
from django.db import models
class UserEntity(models.Model):
# 默认情况下会自动创建id主键
name = models.CharField(max_length=20)
age = models.IntegerField(default=0)
phone = models.CharField(max_lengt=11)
class Meta:
# 指定当前模型类映射成哪一个表
db_table = 'app_user'
模型创建完成后,先后执行生成迁移文件和迁移。
2.3 CURD操作
查询 READ
UserEntity.objects.all() # 查询所有, list
UserEngtity.objects.get(pk=id) # 根据主键值查询一个实体对象
增加 CREATE
u = UserEntity()
u.name = 'disen'
u.age = 20
u.phone = '177'
# 保存模型对象
u.save()
删除Delete
u = UserEntity.objects.get(1)
u.delete() # 删除
更新Update
u = UserEntity.objects.get(3)
u.name = '李成'
u.save()
三、站点管理
注意:确定数据库已迁移
3.1 创建超级用户
python manager.py createsuperuser
根据提示输入用户名、邮箱和口令
启动服务后,可以在/admin页面进行登录
3.2 定制admin管理
3.2.1 注册自己的模块
在自己模块的admin.py文件中
admin.site.register(Store)
3.2.2 自定义表单
在admin.py文件中,定义admin.ModelAdmin的子类
1) 效果: 添加Store的表单中只添加name
class StoreAdmin(admin.ModelAdmin):
fields = ('name',)
admin.site.register(Store, StoreAdmin)
2) 效果: 分栏显示
class StoreAdmin(admin.ModelAdmin):
fieldsets = (['Main', {'fields': ('name',)}],
['Advance', {'fields': ('address',),
'classes': ('collapse',)}])
3) 效果: 内联显示
# 为外表创建内联类
class FruitInline(admin.TabularInline):
model = Fruit
# 在主表设置内联
class StoreAdmin(admin.ModelAdmin):
inlines = [FruitInline]
3.2.3 列表显示与搜索
# 在admin.ModelAdmin的子类中
class StoreAdmin(admin.ModelAdmin):
list_display = ('id', 'name','address') # 列表显示
search_fields = ('name','address') # 搜索关键字的字段
admin.site.register(Store, StoreAdmin)
四、 综合案例-水果管理
3.1 模型设计
# Fruit 水果模型类(name, price, source, cate_type_id)
# FruitImage 水果图片模型类(fruit_id, url, width, height, name)
# CateType 水果分类(name, order_num)
# Store 水果商店(name,name,boss_name, phone, address, city, lat, lon)
# StoreDetail 水果商店的详情
3.2 模板的基本使用
循环语句块
{% for item in items %}
{% endfor %}
分支循环
{% if 条件表达式 %}
{% endif %}
变量
{{ 变量名 }}
在views.py视图函数中,渲染模板
return render(request, 'fruit/list.html', locals() )
3.3 页面设计
{% block name %}
{% endblock %}
{% extends "base.html" %}
五、ORM快速应用
5.1 字段类型
-
CharField
字符类型,必须指定max_length属性
-
IntegerField
数值类型,可以指定chiose为元组,表示选择范围
-
BooleanField
布尔类型, 数据表中表现是0 或 1
-
NullBooleanField
可以为空的布尔值
-
AutoField
自增列 int类型。必须填入参数 primary_key=True;可选auto_create自增
-
FloatField
浮点类型
-
DecimalField
同Python的Decimal类型,参数有
- max_digits 最大总位数
- decimal_places 小数点后的位数
-
TextField
文本类型
-
UUIDField
字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证
class Order(models.Model): no = models.UUIDField(verbose_name='订单编号') price = models.DecimalField(verbose_name='订单金额',max_digits=6, decimal_places=2) pay_state = models.BooleanField(default=False)
使用Order创建对象(数据库增加数据)方式如下:
import uuid Order.objects.create(no=uuid.uuid4(),price=1819.567,pay_state=True) # price只保留两位小数,会自动四舍五入
-
FileField
字符串,路径保存在数据库,文件上传到指定目录
参数有如下内容:upload_to = "" 上传文件的保存路径 storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
-
ImageField
字符串,路径保存在数据库,文件上传到指定目录
参数有:upload_to = "" 上传文件的保存路径 storage = None 存储组件,默认django.core.files.storage.FileSystemStorage width_field=None, 上传图片的高度保存的数据库字段名(字符串) height_field=None 上传图片的宽度保存的数据库字段名(字符串)
-
DateField
日期类型
格式:YYYY-MM-DD
参数
auto_now
每次保存时,自动设置当前字段为当前时间
用于“最后一次修改时间”
auto_now_add
对象每一次保存时,自动设置为当前时间
用于“创建时间”
注意
auto_now和auto_now_add及default只能设置一个,不能组合 -
DateTimeField
日期时间类型
datetime.datetime
日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] -
TimeField
时间类型
格式: HH:MM[:ss[.uuuuuu]]
5.2 约束
-
max_length
最大长度 -
default
默认值 -
unique
唯一 -
primary_key
主键 -
null
不为null
False, 不能为null
默认
True , 可以为null -
blank
是否允许用户输入为空
即空字符串 -
db_index
索引 -
db_column
指定字段名 -
verbose_name
在admin显示的字段名称 -
choices
一个包含双元素元组的可迭代的对象,用于给字段提供选项
如sex_l = ( (1,'男'), (2,'女') ) sex = color = models.IntegerField(choices=sex_l, defalut=1)
5.3 FileField和ImageField
文件字段和图片字段都属性MEDIA的多媒体类型的文件,需要在settings.py设置脚本文件中指定MEDIA_ROOT、MEDIA_URL、STATIC_URL, STATICFILES_DIRS
使用ImageField时,必须安装Pillow库
pip install pillow
扩展: github: https://github.com/disenQF/StoreOA.git
5.4 模型的Meta元信息
在模型类中,声明内部类 Meta, 类成员可以如下的变量:
- db_table
- ordering
- verbose_name
- verbose_name_plural
- unique_together
- abstract 布尔类型,表示当前的模型类是否为抽象类,如果抽象类,则不会创建表
六、CURD深度使用
6.1 模型类的objects
默认情况下,由创建模型类的元类在模型类中创建django.db.models.Manager类的对象,并赋给objects。Manager类实际是QuerySet类的子类。
我们可以在模型类中, 创建objects, 但是必须为Manager类对象。不能是普通的字段。
class CateTypeEntity(models.Model):
name = models.CharField(max_length)
# objects = models.IntegerField(default=0) # 错误的写法
objects = models.Manager() # 正确的写法
6.2 filter和exclude查询
模型类.objects.filter(属性名__条件=条件值)
模型类.objects.filter(属性名=条件值)
模型类.objects.filter(属性名__时间属性__条件=条件值)
条件包含
- 大于 gt、小于 lt、大于等于 gte、小于等于lte
- 字符串相关: contains 包含(区分大小写), icontains, (i)startswith, (i)endswith
- null相关: isnull(), isnotnull()
- 范围: in
时间属性包含
- year, month, day
- hour, minute, second
6.3 QuerySet对象的方法
QuerySet对象的本身是可以被迭代的。
返回QuerySet对象的方法有:
- filter()
- exclude()
- all()
- values()
- values_list()
- order_by(‘name’, ‘-city’)
统计方法和判断是否存在数据方法
- count()
- exists()
6.4 聚合函数类
django.db.models.Count/Avg/Max/Min/Sum与QuerySet的aggregate()组合使用。
七、F和Q的用法
7.1 F的选择字段值
django.db.models.F 用于获取字段的值并参于计算或作业更新条件。
# 中秋节: 全场水果打8.8折扣
FruitEntity.objects.update(price=F('price')*0.88)
7.2 Q的多条件
Q是用来指定多个查询条件的逻辑关系: 且 & , 或 | , 非 ~
# 查询价格低于1的,或高于200的水果, 或源产地是西安且名字中包含"果"
fruits2 = FruitEntity.objects.filter(
Q(price__lte=1) | Q(price__gte=200) | Q(Q(source='西安') & Q(name__contains="果"))).values()
八、原生的SQL语句查询
针对复杂查询来说, 通过QuerySet查询不是特别方便,则使用原生的SQL查询。
-
QuerySet提供两种原生SQL查询:
-
QuerySet.raw()
要求: 查询的字段必须是模型类中声明的字段,且必须存在主键列 。查询的结果是RawQuerySet类对象,可以迭代,元素类型是模型类对象。
另外, 查询sql语句中可以使用 “%s” 占位符, 在其它可以使用元组参数传值
raw_queryset = FruitEntity.objects.raw('select id, name,price from t_fruit where price < %s order by price DESC LIMIT %s, 10', (10, 0)) for fruit in raw_queryset: print(fruit)
-
QuerySet.extra()
extra()扩展查询, 针对QuerySet查询结果集中,额外增加查询条件或排序等相关操作。返回结果还是QuerySet对象
qs1 = FruitEntity.objects.extra(where=['price<%s'], params=['10']) qs2 = FruitEntity.objects.extra(where=['price<%s or name like %s'], params=['2', '果']) qs3 = FruitEntity.objects.extra(where=['price<%s or name like %s', 'source=%s'], params=['2', '果', '西安'])
-
-
使用django.db.connection数据库连接对象进行原生SQL查询
connection对象表示与数据库连接的对象, 可以通过connection连接对象获取游标cursor对象,再通过cursor的execute()/fetchall()/rowcount相关方法或函数来执行原生的SQL和执行的结果。
cursor = connection.cursor() cursor.execute('select * from t_fruit') for row in cursor.fetchall(): print(row)
cursor.execute('update t_fruit set price=2 where id=1') print(cursor.rowcount) connection.commit() # 提交更新
九、模型类之间的关系
9.1 显性创建objects
class OrderManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(~models.Q(pay_status=5))
# 统计2018年全年销售总额
OrderModel.objects.filter(create_time__year=2018) \
.aggregate(total_price=Sum('price'))
9.2 一对一关系
一对一的关系可以通过models.OneToOneField(关联模型类, on_delete=models.CASCADE)建立,
on_delete除了CASCADE级联删除之外,还有model.SET_NULL级联设置为null。
class RealProfile(models.Model):
# 声明一对一的关联关系
user = models.OneToOneField(UserEntity,
verbose_name='账号',
on_delete=models.CASCADE)
real_name = models.CharField(max_length=20,
verbose_name='真实姓名')
number = models.CharField(max_length=30,
verbose_name='证件号')
real_type = models.IntegerField(verbose_name='证件类型',
choices=((0, '身份证'),
(1, '护照'),
(2, '驾驶证')))
image1 = models.ImageField(verbose_name='正面照',
upload_to='user/real')
image2 = models.ImageField(verbose_name='反面照',
upload_to='user/real')
主表: 用户表 , 从表: 实名认证表
从表对象获取 主表的数据
u1 = RealProfile.objects.filter(real_name='狄清').first()
u1.user.phone # 直接访问主表对象的数据
主表中获取从表的数据
login_u1 = UserEntity.objects.get(pk=1)
# 以隐性方式 读取从表的数据: 对象.关联模型类全小写名称.属性
login_u1.realprofile.number # realprofile 一对一的关系模型类的名称(全小写)
9.3 一对多或多对一的关系
# 声明水果商品与购物车的关系表
class FruitCartEntity(models.Model):
cart = models.ForeignKey(CartEntity,
on_delete=models.CASCADE,
verbose_name='购物车')
fruit = models.ForeignKey(FruitEntity,
on_delete=models.CASCADE,
verbose_name='水果名')
cnt = models.IntegerField(verbose_name='数量',
default=1)
def __str__(self):
return self.fruit.name +':'+self.cart.no
@property
def price1(self):
# 属性方法在后台显示时没有verbose_name, 如何解决?
return self.fruit.price # 从获取主的对象属性
@property
def price(self):
# 属性方法在后台显示时没有verbose_name, 如何解决?
return round(self.cnt*self.fruit.price, 2)
class Meta:
db_table = 't_fruit_cart'
verbose_name_plural = verbose_name = '购物车详情表'
# 主读取多个从对象的信息
login_u = UserEntity.objects.get(pk=1)
# 查询当前用户的购物车中的所有商品及数量相关的信息
cart_fruits = login_u.cartentity.fruitcartentity_set.all()
for fruit_cart in cart_fruits:
print(fruit_cart.fruit.name, fruit_cart.fruit.price, fruit_cart.cnt)
9.4 多对多
django提供models.ManyToManyField 字段,来实现多对多的关系,需要第三方表的外键来实现。
如需求: 用户收藏商品, 需要建立第三方表,完成用户收藏多个商品, 或一个商品被多位用户收藏。
在FruitEntity模型类中,增加users属性,内容如下:
# 默认情况下,反向引用的名称是当前类的名称(小写)_set
# 可以通过related_name 来指定
# db_table='t_collect' 使用第三张表建立fruit和user的多对多关系
users = models.ManyToManyField(UserEntity,
db_table='t_collect',
related_name='fruits',
verbose_name='收藏用户列表')
当迁移完成后,模拟用户收藏商品:
u1 = UserEntity.objects.get(pk=1)
u1.fruits.add(FruitEntity.objects.get(pk=1))
u1.fruits.add(FruitEntity.objects.get(pk=2))
u2 = UserEntity.objects.get(pk=2)
u2.fruits.add(FruitEntity.objects.get(pk=2))
查询某一件商品,被哪些用户收藏
fruit1 = FruitEntity.objects.get(pk=2)
fruit1.users.all()
用户取消收藏商品
u1.fruits.remove(FruitEntity.objects.get(pk=1))
练习任务: 增加标签模型类TagEntity(id, name, order_num)并且和商品建立多对多的关系
十、模板语法
10.1 MTV设计中TV的关系
- V 视图理函数可以渲染(使用)多个模板
- 一个模板 T 可被任意的V 视图函数使用
10.2 模板的加载过程
模板加载对象: django.template.loader
- 加载
template = loader.get_template('index.html')
- 渲染
html = template.render(context) # context是一个dict类型对象
- 加载+渲染
html = loader.render_to_string("index.html", context)
10.3 模板中使用 “.” 点语法
使用 “.” 访问变量Variable的属性, 系统尝试以下顺序查询:
- 字典
- 属性或方法
- 列表的数值索引
<h3>{{ msg }}</h3>
<p style="color: green">
第三个用户名: {{ users.2.name }}
</p>
<p style="color: red;">
请客的人: {{ error_index }}
</p>
<p style="color: white;background-color:blue;">
<span>VIP:</span>
<span>{{ vip.name.upper }}-{{ vip.money }}</span>
</p>
<ul>
{% for key, value in vip.items %}
<li>{{ key }} = {{ value }}</li>
{% endfor %}
</ul>
<ul>
{% for user in users %}
<li>{{ user.id }} {{ user.name }}</li>
{% if forloop.counter0 == error_index %}
<p style="color: red;">
请客的人: {{ user.name }}
</p>
{% endif %}
{% endfor %}
</ul>
users = UserEntity.objects.all()
msg = '最优秀的学员'
error_index = random.randint(0, users.count()-1)
vip = {
'name': 'disen',
'money': 20000
}
# # 加载模板
# template = loader.get_template('user/list.html')
#
# # 渲染模板
# html = template.render(context={
# 'msg': msg,
# 'users': users
# })
html = loader.render_to_string('user/list.html',
locals())
return HttpResponse(html,
status=200) # 增加响应头??
10.4 表达式标签
- {% if 条件 %} {% endif %}
- 条件表达式支持关系运算符
or
and
not
in
- == 、 !=、 > 、< 、>=、<=
- 条件表达式支持关系运算符
- {% ifeqaul 值1 值2 %} {% endifequal %}
- {% ifnoteqaul 值1 值2 %} {% endifnotequal %}
- {% for 变量 in 可迭代对象 %} {% endfor %}
- {% empty %} 当可迭代对象为空(非None), 显示empty标签下面的内容
- {% cycle 值1 值2 值3 值4 %}
- {{ forloop.counter }} 循环记数器, 从1开始
- 注释: 渲染模板之后不会存在的
- {# 单行注释 #}
- {% comment %} 多行注释的文本 {% endcomment %}
- escape 安全标签
- {% autoescape on|off %} 开启escape时, 会将变量的 大于号、小于号、单引号、双引号及&等转成escape的表示,如大于号为 >
- {{ info|escape }} escape也可以换成safe 表示不转换escape
10.5 模板的过滤器
-
数值运算
- |add:5
- |add:-5
- |divisibleby:2
- {% widthratio 变量 分母 分子 %}
-
字符串
-
格式化
-
日期格式化
now|date:“Y-m-d H:i:s”
-
文件大小格式化
file_size|filesizeformat
-
小数值格式化
v|floatformat:n 默认n 是1位小数
-
-
列表
-
HTML转义
{{ html|safe }} 不转义
{{ html|escape }} 转义, 显示html源码标签
-
默认值
10.6 自定义过滤器
在app的__init__.py脚本编写
from django.template.defaultfilters import register
import os
@register.filter('ellipse')
def ellipse(value):
return os.path.split(value)[-1]
10.7 扩展: os.stat()获取文件大小
file_dir = os.path.join(settings.BASE_DIR, 'mainapp/')
files = {file_name: os.stat(file_dir+file_name)
for file_name in os.listdir(file_dir)
if os.path.isfile(file_dir+file_name)}
十一、csrf (防止跨站请求伪造)
11.1 {% csrf_token %} 标签
在 模板的<form>内部使用即可,会生成隐藏字段, 名称为csrfmiddlewaretoken, 它的值是在渲染板块是产生的,并存储在session, 当表单提交到后端时,通过csrfMiddleWare中间件验证。
<form class="form" method="post">
{% csrf_token %}
</form>
注意: 只针对post请求
扩展1: make_password和check_password
django.contrib.auth.hashers.make_password
django.contrib.auth.hashers.check_password
扩展2: request.session
session是字典类型
11.2 取消csrf
- 在settings.py的中间件的配置中,将CsrfViewMiddleware删除
- @csrf_exempt装饰view处理函数
django.views.decorators.csrf.csrf_exempt
十二、模板布局标签
12.1 block/extends/include
12.2 显示父模板的内容
{{ block.super }}
十三、app模块内部模板
- 每个app下都可以增加templates目录,存放它自己的模板文件
- 内部的模板templates目录,不需要在settings.py中设置
- 如果app模块之外存在templates目录,且在settings.py中已设置,则加载模板时,则优先从此目录中加载模板文件。
十四、URL路由配置
14.1 URL分级
URL分级即是总路由和子路由(app模块的路由)
- 主工程目录下urls.py
urlpatterns = [
path('url', 视图函数, name=None),
path('url/', include('app_label.urls', namespace=None)) # 包含子路由
]
- app目录下的urls.py
urlpatterns = [
path('url', 视图函数, name=None),
]
include的namespace和path的name都在反向解析中使用, 即反向获取url路径: ‘namespace.name’
14.2 url和path两种路由的配置
url()配置兼容Django1.x 的老版本
path() 是Django2之后的路由函数。
from django.urls import path
from django.conf.urls import url
from orderapp import views
urlpatterns = [
path('list', views.order_list),
url(r'^list2$', views.order_list)
]
url()支持正则, 通过正则在url路径中向处理函数传参:
url(r'^list2/(?P<city_code>\w+)/(?P<order_num>\d+)$', views.order_list)
以上是按关键传参方式。也可以按位置传参(从左到右),如下所示
url(r'^list2/(\w+)/(\d+)$', views.order_list)
def order_list(request, order_num, city_code):
print(order_num, city_code)
return render(request,
'list_order.html',
locals())
以上的url路由传参可以使用path()的<name>实现, 如:
path('list/<city_code>/<order_num>', views.order_list),
如果路由中的参数是uuid类型,则使用参数转换器进行匹配, 如
path('cancel/<uuid:order_num>', views.cancle_order),
除了uuid转换器之外, 还有str, int, slug。如果路由中参数的规则较复杂时,建议使用re_path()配置路由中的参数
re_path(r'^search/(?P<phone>1[3-57-9][\d]{9})$', views.search)
def search(request, phone):
return HttpResponse('hi, phone: %s' % phone)
十五、反向解析
15.1 命名空间
使用include的namespace和path的name属性。
主路由
path('order/', include('orderapp.urls', namespace='order')),
子路由内容如下:
app_name = 'orderapp'
urlpatterns = [
path('list/<city_code>/<order_num>', views.order_list, name='list'),
path('cancel/<uuid:order_num>', views.cancle_order, name='cancel'),
re_path(r'^search/(?P<phone>1[3-57-9][\d]{9})$', views.search, name='search')
# url(r'^list2/(?P<city_code>\w+)/(?P<order_num>\d+)$', views.order_list)
]
【注意】如果子路由指定了namespace命名空间, 则子路由的脚本中必须声明"app_name"属性,属性一般是app模块名称。
15.2 在网页中获取路径
在网页中使用 {% url ‘namespace或app_name:name’ 参数 %}
<p>
<a href="{% url 'orderapp:list' 'xa' 1001 %}">订单</a>
</p>
参数可以是多个,每个参数之间使用空格分隔。
参数默认使用位置传参, 也可以使用关键参数传参。
<p>
<a href="{% url 'orderapp:list' order_num=1002 city_code='xa' %}">订单</a>
</p>
15.3 在视图函数中获取路径
在视图函数中,使用reverse()函数来反向获取url请求路径。 再通过redirect或HttpResponseRedirect()来重定向。
url = reverse('order:search',
args=('17791692077',))
return redirect(url)
url = reverse('order:list',
kwargs=dict(city_code='ShangXiXiaan', order_num=11009))
return HttpResponseRedirect(url)
-
reverse()可以使用kwargs字典类型传参, 也可以使用args以位置方式传参。
-
HttpResponseRedirect()和redirect()是一样的, 即redirect()返回就是HttpResponseRedirect类对象。
十六、error视图模板
常见的错误的响应状态码: 403, 400, 404, 405 请求方法不允许, 500 (服务器异常)
在templates模板中定义404.html或500.html, 要求将settings.py的DEBUG设置为False。
404.html
{% extends 'base.html' %}
{% block content %}
<h3 style="color:red">
Sorry, 您请求的资源{{ request_path }}
<script>
document.write(window.location.href)
</script> 不存在
</h3>
<p>
3秒之后自动跳转到<a href="/">主页</a>
</p>
{% endblock %}
十七、模型类扩展知识点
17.1 validators验证
如果验证不通过,可以抛出ValidationError信息
from django.core.exceptions import ValidationError
自定义验证器类(用于模型类字段的):
class UserValidator:
@classmethod
def valid_phone(cls, value):
if not re.match(r'1[1-57-9]\d{9}', value):
raise ValidationError('手机格式不正确')
return True
class UserEntity(models.Model):
name = models.CharField(max_length=20,
verbose_name='账号')
age = models.IntegerField(default=0,
verbose_name='年龄')
phone = models.CharField(max_length=11,
verbose_name='手机号',
validators=[UserValidator.valid_phone],
blank=True, # 站点的表单字段值可以为空
null=True) # 数据表的字段可以是null值
在model.CharField(validators=[]) 指定哪些验证方法。
17.2 QuerySet的bulk_create([]) 批量创建
c1 = CateTypeEntity()
c1.name='水果1'
c1.order_num = 10
c2 = CateTypeEntity()
c2.name = '水果2'
c2.order_num = 11
CateTypeEntity.objects.bulk_create([c1, c2])
17.3 QuerySet.values()或values_list()返回指定字段
UserEntity.objects.values('id', 'name') # 只查看id和name两个字段
<QuerySet [{'id': 1, 'name': 'disen'}, {'id': 2, 'name': 'jack'}, {'id': 3, 'name': '王栋平'}, {'id': 7, 'name': '罗鹏'}, {'id': 8, 'name': '李晨西'}, {'id': 10, 'name': '疾风剑豪亚索'}, {'id': 11, 'name': 'lucy'}]>
17.4 request请求对象的属性
GET/POST/COOKIES/FILES 都是QueryDict类,QueryDict自动进行url的中文编码处理。
method, path, content_type, encoding, session