目录
一、创建Django项目工程
二、项目文件目录
三、Django的url部分
四、Django视图
五、Django模板
六、模型
七、Form操作
Django是MVT模式的python的web框架
M:Model层与MVC模式中的Model层功能大致相同
V:view与MVC中C大致相同,用来处理访问
T:template与MVC中的V大致相同,用于返回页面
在终端输入:django-admin startproject projectName
其他常用命令:
python manage.py runserver ip:port # 启动一个web服务
python manage.py startapp appname # 创建一个app项目
python manage.py makemigrations # 生成数据库迁移文件
python manage.py migrate #生成迁移
python manage.py createsuperuser # 创建一个管理员账户,用于登录Django自带后台
manage.py:一个命令行工具,可以使你用多种方式对Django项目进行交互
内层的目录:项目的真正的Python包
_init _.py:一个空文件,它告诉Python这个目录应该被看做一个Python包
settings.py:项目的配置
urls.py:项目的URL声明
wsgi.py:项目与WSGI兼容的Web服务器入口
创建好工程之后,我们还需要创建一个app,而这个app就是我们想要书写的项目
执行之前我们说过的命令来创建一个应用,在终端执行命令:python manage.py startapp app01,到这里我们便创建了一个名为app01的应用,此时再看整个工程的目录如下:
app01文件夹:我们创建的a
pp的目录,用来存放app的内容
models.py:用来创建一个数据模型,与数据库操作相关,存入或读取数据时用到这个
views.py:用来书写视图函数的文件
migrations文件夹:用来存放数据库生成迁移的文件,当执行python manage.py makemigrations之后,该文件夹下便会生成新的迁移文件,执行python manage.py migrate命令根据新生的文件夹,对数据库表结构进行修改
项目下的urls.py文件的注释
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.conf.urls import url, include
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
通过上面这段文字,我们可以知道url可以有多种对应方式,可以直接对应视图函数,可以对应类中的函数,还可以引入额外的url文件的配置
虽然我们可以在工程目录下的urls.py文件书写路由,但是,不利于管理,因此我们可以在每个app内创建一个py文件来创建属于每个app自己的路由
app01/urls.py文件的内容
from django.conf.urls import url
from app01 import views # 导入app01目录下的views文件
urlpatterns = [
# url(正则表达式,视图函数,关键字参数,别名)
url(r'^$', views.index, name="index"),
]
关于name="index":在html页面中通过{% url 'index' %}即可在页面中得到该url,即使正则匹配部分发生改变,也不需要在html页面中修改url地址,减少网页硬编码,不理解也没事,记住这样做就行
此时还需要在项目的mysite/urls.py文件中进行修改
修改如下
from django.conf.urls import url, include
from django.contrib import admin
urlpatterns = [
# url(正则表达式,视图函数,关键字参数,别名)
# django项目自带后台管理的对应url
url(r'^admin/', admin.site.urls),
# 指向app01中的url文件,当匹配到这一条url后将进入app01/urls.py文件中继续进行匹配
url(r'^', include("app01.urls"))
]
Django的路由支持正则匹配,
url(r'^year/(\d{4})/(\d{2})$', views.year),
# 可以为传入的参数指定名字
url(r'^(?P(\d+))/(?P(\d+))$', views.year_month),
url(r'^(?P(\d+))/(?P(\d+))/(?P(\d+))$', views.year_month_day, name="ymd"),
对应的视图函数是
def year(request, *args):
print(*args)
return HttpResponse("sucess")
def year_month(request, year,month):
print(year,month)
return HttpResponse("year_month")
Django中的视图函数主要是接收浏览器发送过来的数据,进行逻辑处理然后返回用户想要得到的内容
主要写在views.py文件中
views.py
def year(request, *args):
print(*args)
return HttpResponse("sucess")
def year_month(request, year,month):
print(year,month)
return HttpResponse("year_month")
def year_month_day(request, *args, **kwargs):
print(args)
print(kwargs)
return HttpResponse("year_month_day")
views.py中的函数必须拥有返回值,并且函数的第一个参数必须是request,因为需要处理request请求,后面的便是自定义的参数,自定义的参数可以是位置参数,可以可变长度参数,也可以是键值对形式的字典。
关于视图函数的返回,通常我们可以利用下面这三个函数
查看源码可知:
HTTPResponse()返回一个字符串
HttpResponse(HttpResponseBase):
"""
An HTTP response class with a string as content.
This content that can be read, appended to or replaced.
"""
render()函数的第一参数必须是request,第二个是我们要返回的模板,context可以是我们要在模板中渲染的数据
render(request, template_name, context=None, content_type=None, status=None, using=None):
"""
Returns a HttpResponse whose content is filled with the result of calling
django.template.loader.render_to_string() with the passed arguments.
"""
redirect()重定向函数,常用于页面的重定向,比如登录后自动跳转到个人中心等
redirect(to, *args, **kwargs):
"""
Returns an HttpResponseRedirect to the appropriate URL for the arguments
passed.
The arguments could be:
* A model: the model's `get_absolute_url()` function will be called.
* A view name, possibly with arguments: `urls.reverse()` will be used
to reverse-resolve the name.
* A URL, which will be used as-is for the redirect location.
By default issues a temporary redirect; pass permanent=True to issue a
permanent redirect
"""
通过查看项目文件的urls.py文件,我们可以发现views.py文件中除了直接写函数外,还可以写类来实现相同的功能
Django中的模板可以说是我们通常说的html文件,但是又和普通的html文件有所不同,因为这里的模板可以被继承,导入
如果视图函数返回一个简单的页面,那我们就可以直接返回页面,比如
index
首页
此时我们可以得到一个首页的页面,通常首页的顶部的导航条在其他页面中也能看到,那我们总不能在每个需要的导航条的页面都写上导航条的代码,这时我们就可以使用模板的继承了。修改后代码如下
首先创建一个base.html,代码如下
{% block title %}
base
{% endblock %}
{% block nav %}
导航条
{% endblock %}
{% block content %}
首页
{% endblock %}
{% block footer %}
{% endblock %}
将index.html的代码修改如下
{% extends 'base.html' %}
index
{% include 'my.html' %} #另一种方式来实现公共元素的使用
{% block content %} #覆盖base.html中 block名字为content块中的内容
{{ block.super }} # 会保留原block中的内容
index
{% endblock %}
当我们再次访问index.html的页面时,可以看到页面上不仅有index,还有导航条。因为index页面继承了base的元素。
要求:extends继承页面时,继承语句之前不能有任何的html标签。通过block语句我们可以将继承的页面中的block块覆盖掉,当我们想在原block的基础上进行添加时,我们需要在block的中写上{{ block.super }}。
使用继承的同时,也继承了父页面的的布局。总之,想要公用哪部分元素就把这一部分放到block块中。
PS:除此之外,对于公共的内容,我们还可以利用include来引入内容,例如:nav.html文件,我们想要在多个文件中使用的话,我们需要使用{% include 'nav.html' %}来进行使用
模板语言的内容解析:
在模板中我们可以使用循环,判断,列表,字典,过滤器等
首先是循环:
视图函数,通过render返回一个页面,同时返回一个字典,如果不想返回字典的形式,想要返回index函数中所有的变量
可以在字典位置使用local()函数
def index(request):
m_l = [1, 2, 3, 4, 5, 6]
return render(request, 'indedx.html', {"my_list": m_l})
模板,将index中对应位置的代码修改如下,再次访问,页面会增加1 2 3 4 5这几个数。
{% block content %}
{% for i in my_list %}
{{ i }}
{% endfor %}
{% endblock %}
for循环,if判断有开始有结束。语法如下{% for i in k%}{% endfor %};{% if i %}{% endif %}
通过模板的来实现变量的遍历。{{ 要显示的变量 }},除此之外,在for循环中,Django还提供了一遍for循环中可能用到的变量
变量 作用
forloop.counter 索引从 1 开始算
forloop.counter0 索引从 0 开始算
forloop.revcounter 索引从最大长度到 1
forloop.revcounter0 索引从最大长度到 0
forloop.first 当遍历的元素为第一项时为真
forloop.last 当遍历的元素为最后一项时为真
forloop.parentloop 用在嵌套的 for 循环中,获取上一层 for 循环的 forloop
forloo.xxxx还可以与if语句用。
循环中可能会出现空值,比如字典{"name":""},当循环到这里时,我们可以使用{% empty %}来提示遇到了空值,然后会输出想要的语句
示例
{% block content %}
{% for i in my_dic %}
{{ i.name }}
{% empty %}
名字为空
{% endfor %}
对字典per = {"name":"ajune"},取值时不能per["name"],这样取值了,此时需要利用.来取值,例如per.name即可
Django中ORM很强大,
对象关系映射(Object Relational Mapping),它的实质就是将关系数据(库)中的业务数据用对象的形式表示出来,并通过面向对象(Object-Oriented)的方式将这些对象组织起来,实现系统业务逻辑的过程。
在ORM过程中最重要的概念是映射(Mapping),通过这种映射可以使业务对象与数据库分离。从面向对象来说,数据库不应该和业务逻辑绑定到一起,ORM则起到这样的分离作用,使数据库层透明,开发人员真正的面向对象。
Django中Model中常用字段,通过这些字段的组合,可以构建出数据库表对应的Model
AutoField(Field) - int自增列,必须填入参数 primary_key=True;
django中一般默认自动为我们添加自增字段id,并且默认为主键。
如果不想要django自动添加的,那边可以用这个字段来自定义了,一旦自定义,django将不会自动添加。
IntegerField(Field) - 整数列(有符号的) -2147483648 ~ 2147483647
BooleanField(Field) - 布尔值类型
NullBooleanField(Field) - 可以为空的布尔值
CharField(Field) - 字符类型- 必须提供max_length参数, max_length表示字符长度
TextField(Field) - 文本类型
EmailField(CharField): - 字符串类型,Django Admin以及ModelForm中提供验证机制
IPAddressField(Field) - 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制
GenericIPAddressField(Field)
- 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
- 参数:
protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启此功能,需要protocol="both"
URLField(CharField) - 字符串类型,Django Admin以及ModelForm中提供验证 URL
SlugField(CharField) - 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)
CommaSeparatedIntegerField(CharField) - 字符串类型,格式必须为逗号分割的数字
UUIDField(Field) - 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证
FilePathField(Field) - 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
- 参数:
path, 文件夹路径
match=None, 正则匹配
recursive=False, 递归下面的文件夹
allow_files=True, 允许文件
allow_folders=False, 允许文件夹
FileField(Field)
- 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = "" 上传文件的保存路径
storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
ImageField(FileField)
- 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = "" 上传文件的保存路径
storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
width_field=None, 上传图片的高度保存的数据库字段名(字符串)
height_field=None 上传图片的宽度保存的数据库字段名(字符串)
DateTimeField(DateField) - 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
DateField(DateTimeCheckMixin, Field) - 日期格式 YYYY-MM-DD
TimeField(DateTimeCheckMixin, Field) - 时间格式 HH:MM[:ss[.uuuuuu]]
而对于字段,每个字段还拥有一系列的参数
null 数据库中字段是否可以为空
db_column 数据库中字段的列名
db_tablespace
default 数据库中字段的默认值
primary_key 数据库中字段是否为主键
db_index 数据库中字段是否可以建立索引
unique 数据库中字段是否可以建立唯一索引
unique_for_date 数据库中字段【日期】部分是否可以建立唯一索引
unique_for_month 数据库中字段【月】部分是否可以建立唯一索引
unique_for_year 数据库中字段【年】部分是否可以建立唯一索引
verbose_name Admin中显示的字段名称
blank Admin中是否允许用户输入为空
editable Admin中是否可以编辑
help_text Admin中该字段的提示信息
choices Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
如:gf = models.IntegerField(choices=[(0, '李白'),(1, '杜甫'),],default=1)
error_messages 自定义错误信息(字典类型),从而定制想要显示的错误信息;
字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date 如:{'null': "不能为空.", 'invalid': '格式错误'}
validators 自定义错误验证(列表类型),从而定制想要的验证规则
from django.core.validators import RegexValidator
from django.core.validators import EmailValidator,URLValidator,DecimalValidator,\ MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
如:
test = models.CharField(
max_length=32,
error_messages={
'c1': '优先错信息1',
'c2': '优先错信息2',
'c3': '优先错信息3',
},
validators=[
RegexValidator(regex='root_\d+', message='错误了', code='c1'),
RegexValidator(regex='root_112233\d+', message='又错误了', code='c2'),
EmailValidator(message='又错误了', code='c3'), ]
)
class UserInfo(models.Model):
nid = models.AutoField(primary_key=True)
username = models.CharField(max_length=32)
class Meta:
# 数据库中生成的表名称 默认 app名称 + 下划线 + 类名
db_table = "table_name"
# 联合索引
index_together = [
("字段1", "字段2"),
]
# 联合唯一索引
unique_together = (("字段1", "字段2"),)
# admin中显示的表名称
verbose_name =”用户信息”
# verbose_name加s
verbose_name_plural
在Django的Models.py定义表结构,利用python manage.py makemigration生成迁移,再利用python manage.py migrate创建数据表,下面是一个例子
# 书
class Book(models.Model):
bookName = models.CharField(max_length=20) #书名
price = models.IntegerField() #价格
publish = models.ForeignKey("Publish") #出版社
authors = models.ManyToManyField("Author") # 作者
def __str__(self):
return self.bookName #当打印对象时,返回书名
#出版社
class Publish(models.Model):
name = models.CharField(max_length=20) #出版社名字
city = models.CharField(max_length=20) #出版社所在城市
def __str__(self):
return self.name #返回出版社名字
#作者
class Author(models.Model):
name = models.CharField(max_length=12) #作者名字
age = models.IntegerField() #年龄
def __str__(self):
return self.name #返回作者名字
当生成数据库表后,数据库中会出现下面几张表
应用名_book,应用名_publish,应用名_author,应用名_book_authors
在生成数据库表时,默认名字是应用名_类名,
但是当一个表中出现了ManyToManyField字段时,django会自动生成一个多对多的表,在这里表名为应用名_book_authors的这张表便是自动创建的多对多的表。
当然我们也可以手动的创建一张多对多的表
class Book_Author(models.Model):
book = models.ForeignKey("Book")
author = models.ForeignKey("Author")
class Meta:
# 联合唯一
unique_together = [
("book", "author")
]
如果多对多表中不需要额外的字段,那么为了方便使用,尽量还是使用Django自动为我们生成的表较好。
下面是Django关于数据库的增删改查
增:
'''
添加数据的两种方式,
方式一:
增加一条数据,可以接受字典类型数据 **kwargs
modes.类名.object.create(字段1=值1,字段2=值2...)
还可以直接传入字段和值组成的字典
models.Book.objects.create(**book)
方式二:需要调用save()方法
obj = models.类名(字段1=值1,字段2=值2...)
#models.Book(**book)
obj.save()
PS:当添加记录时,如果存在外键,有两种方式
方式一:
由于Django的ORM在创建数据库表时,对于表外键,会在外键字段的字段名的后面加上_id,
通过使用字段名_id = 外键id这种方式可以添加
方式二:
由于每条记录对应一个对象,外键也是对应一个对象
所以可以通过外键字段 = 外键对象的方式进行添加
对于多对多:
对象.多对多字段.add(另一张表中的对象或者是id)
eg:
book_obj.authors.add(author_obj)
'''
查:重要的一点,通过get方式查询时,当记录不存在或者记录条数超过一条时 ,均会报错
单表查询
'''
单表查询
'''
book_all = models.Book.objects.all()
# values(字段1[,字段2,...]),结果返回形式
多表查询:
# 搜索时,通过外键名__外键表中的字段来进行搜索
# 当要取出值时通过.来获取值
models.Book.objects.filter(publish__city='上海')
'''
正向查询
主表---》副表----》主表
通过查询主表中的外键字段,获取对应的对象或值后,通过该对象或者值在附表中查询,得到结果
'''
# 查询某个出版社出版的所有书籍
# 通过对象
# 方法一正向查询
book_obj = models.Book.objects.get(bookName="GO")
pub_obj = book_obj.publish
book_list = models.Book.objects.filter(publish=pub_obj)
print(book_list)
# 方法二
pub_obj = models.Publish.objects.filter(name="人民出版社")[0]
book_list = models.Book.objects.filter(publish=pub_obj)
print(book_list)
# 方法三反向查询
pub_obj = models.Publish.objects.filter(name="人民出版社")[0]
book_list = pub_obj.book_set.all()
print(book_list)
# 通过外键字段
# 通过filter value(双下划线)
book_list = models.Book.objects.filter(publish__name="人民出版社")
print(book_list)
# 查找出版了GO书籍的出版社的信息
pub_obj = models.Publish.objects.filter(book__bookName="GO")
print(pub_obj)
pub_obj = models.Book.objects.filter(bookName="GO").values("publish__name")
print(pub_obj)
book_list = models.Book.objects.filter(publish__city="北京")
print(book_list)
双下划线:
'''
双下划线
'''
# 获取个数
#
models.Book.objects.filter(name='seven').count()
# 大于,小于
#
models.Book.objects.filter(id__gt=1) # 获取id大于1的值
models.Book.objects.filter(id__gte=1) # 获取id大于等于1的值
models.Book.objects.filter(id__lt=10) # 获取id小于10的值
models.Book.objects.filter(id__lte=10) # 获取id小于10的值
models.Book.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值
# in
#
models.Book.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据
models.TBook1.objects.exclude(id__in=[11, 22, 33]) # not in
# isnull
models.Book.objects.filter(pub_date__isnull=True)
# contains,字段值中含有该值的记录
#
models.Book.objects.filter(name__contains="ven")
models.Book.objects.filter(name__icontains="ven") # icontains大小写不敏感
models.Book.objects.exclude(name__icontains="ven")
# 其他类似
# __startswith,以xx开头
# __istartswith, 以xx开头,大小写不敏感
# __endswith, 以xx结尾
# __iendswith,以xx结尾,大小写不敏感
# range
#
models.Book.objects.filter(id__range=[1, 9]) # 范围bettwen and
# regex正则匹配,iregex 不区分大小写
#
models.Book.objects.get(title__regex=r'^(An?|The) +')
models.Book.objects.get(title__iregex=r'^(an?|the) +')
# date
#
models.Book.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
models.Book.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))
# year
#
models.Book.objects.filter(pub_date__year=2005)
models.Book.objects.filter(pub_date__year__gte=2005)
前面的查询大多是必须符合两个条件的记录,那如何获取一个区间的信息,或者存在两个条件,但只要符合一个条件即可的记录如何查找?
F,Q查询
# F 可以使用模型的字段A与字段B进行比较,如果A写在了等号的左边,则B出现在等号的右边,需要通过F对象构造,即F对象可以使用字段的值经过运算后在给该字段或者其他字段
#
from django.db.models import F,Q
models.Book.objects.update(num=F('num')+1)
# Q
# 过滤器的方法中关键字参数查询,会合并为And进行
# 需要进行or查询,使用Q()对象
# Q对象(django.db.models.Q)用于封装一组关键字参数,这些关键字参数与“比较运算符”中的相同
# Q对象可以使用&(and)、|(or)操作符组合起来
# 当操作符应用在两个Q对象时,会产生一个新的Q对象
# 使用~(not)操作符在Q对象前表示取反
# 可以使用&|~结合括号进行分组,构造复杂的Q对象
# 过滤器函数可以传递一个或多个Q对象作为位置参数,如果有多个Q对象,这些参数的逻辑为and
# 过滤器函数可以混合使用Q对象和关键字参数,所有参数都将and在一起,Q对象必须位于关键字参数的前面
#
# 方式一:
# Q(id__gt=10)
# Q(id=8) | Q(id__gt=10)
# Q(Q(id=8) | Q(id__gt=10)) & Q(caption='root')
models.Book.objects.filter(Q(id__lt=8) & Q(id__gt=10))
# 或者是
# k = Q(id__lt=8) & Q(id__gt=10)
models.Book.objects.filter(k)
# 方式二:
con = Q()
q1 = Q()
q1.connector = 'OR'
q1.children.append(('id', 1))
q1.children.append(('id', 10))
q1.children.append(('id', 9))
q2 = Q()
q2.connector = 'OR'
q2.children.append(('c1', 1))
q2.children.append(('c1', 10))
q2.children.append(('c1', 9))
con.add(q1, 'AND')
con.add(q2, 'AND')
models.Book.objects.filter(con)
删除:
'''
删除操作:
删除操作可以与查找操作配合使用
查找完成之后使用.delete()方法删除
'''
# models.Tb1.objects.filter(name='seven').delete() # 删除指定条件的数据
models.Book.objects.get(bookName="隋唐英雄传").delete()
models.Book.objects.filter(bookName="计算机基础").delete()
改:推荐使用第一种方式
# 改
# 将指定条件的数据更新,均支持 **kwargs,推荐
models.Book.objects.filter(bookName='GO').update(price=39)
'''
UPDATE `app01_book` SET `price` = 39 WHERE `app01_book`.`bookName` = 'GO'; args=(39, 'GO')
'''
# 先获取指定记录,再更新,费时间;因为先把所有的字段值取出,再更新所有的字段值
obj = models.Book.objects.get(bookName='GO')
obj.price = 12
obj.save()
'''
SELECT `app01_book`.`id`, `app01_book`.`bookName`, `app01_book`.`price`, `app01_book`.`pub_time`, `app01_book`.`publish_id` FROM `app01_book` WHERE `app01_book`.`bookName` = 'GO'; args=('GO',)
UPDATE `app01_book` SET `bookName` = 'GO', `price` = 12, `pub_time` = '2019-01-08 16:00:00', `publish_id` = 15 WHERE `app01_book`.`id` = 1; args=('GO', 12, '2019-01-08 16:00:00', 15, 1)
'''
在Django中每当后端获得前端发送的数据时均须要检验数据的合法性,这样一来我们不得不写一大堆的验证规则,这样无疑是非常麻烦的。
因此我们可以使用Django来帮助我们来完成这些操作。
class Myform(forms.Form):
user = fields.CharField(
max_length=18, # 最大长度
min_length=6, # 最小长度
required=True, # 值不能为空
label="用户名:",
initial="ajune", # 初始化显示
error_messages={ # 错误类型的提示信息
"max_length": "太长了",
"min_length": "太短了",
"required": "此字段不能为空"
}
)
age = fields.IntegerField(
required=True,
label="年龄:",
# 最大值
max_value=100,
# 最小值
min_value=0,
error_messages={
"required": "此字段不能为空",
"invalid": "年龄必须为数字"
}
)
pwd = fields.CharField(
required=True,
min_length=3,
max_length=8,
# 过滤空白
strip=True,
label="密码:",
widget=widgets.PasswordInput,
error_messages={
"max_length": "太长了",
"min_length": "太短了",
"required": "此字段不能为空"
}
)
email = fields.EmailField(
required=True,
label="邮箱:",
error_messages={
"required": "此字段不能为空",
"invalid": "邮箱格式不正确"
}
)
# 自定义验证规则
def mobile_validate(value):
mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
if not mobile_re.match(value):
raise ValidationError('手机号码格式错误')
phone = fields.CharField(
label="手机号:",
# validators=[mobile_validate,],
validators=[
RegexValidator(r'^[0-9]+$', '请输入数字'),
RegexValidator(r'^159[0-9]+$', '数字必须以159开头')
],
# 标签后添加
label_suffix="->"
)
在使用时,我们需要实例化类,将对象传到前端。
后端代码:
def modelformtest(request):
ret = {"status": True, "error": None, "data": None}
if request.method == "GET":
# 传入默认值
# moren = {
# "user": 1233123,
# "age": 1,
# "pwd": 1231233,
# "email": "[email protected]"
# }
# mf = Myform(mren)
# 实例化表单类
mf = Myform()
return render(request, 'form.html', {"form": mf})
elif request.method == "POST":
mf = Myform(request.POST)
if mf.is_valid():
print(mf.cleaned_data)
ret["data"] = mf.cleaned_data
# 如果form中的字段和数据库中的字段同名,则直接按照下列方法添加
# models.Book.objects.create(**mf.cleaned_data)
# 指明向前端发送json数据, content_type="application/json"
return HttpResponse(json.dumps(ret))
else:
print(mf.errors)
ret['error'] = mf.errors
return HttpResponse(json.dumps(ret))
前端代码:
label,定义的内容,如果后端没指定将会显示默认值段的值,例如user
form.user生成指定的插件,即html标签,
form.user.errors.0显示错误信息的第一条
{{ form.user.label }}{{ form.user }}{{ form.errors.user.0 }}
{{ form.pwd.label }}{{ form.pwd }}{{ form.errors.pwd.0 }}
{{ form.age.label }}{{ form.age }}{{ form.errors.age.0 }}
{{ form.email.label }}{{ form.email }}{{ form.errors.email.0 }}
{{ form.phone.label }}{{ form.phone }}{{ form.errors.phone.0 }}
这段代码在前端会自动生成指定的html标签,当数据提交到后端时,需要调用先实例化对象mf = Myform(request.POST),将前端发送的数据作为参数传入,然后通过mf.is_valid()来验证数据的合法性。而此时前端的数据将会保存在mf.cleaned_data中,
如果有数据不合法,将会将错误的信息保存到mf.errors中。
当使用Django的Form表单的功能时,每个字段都会存在默认的验证规则用于对数据进行验证,除此之外,还可以通过
validators=[
RegexValidator(r'^正则表达式1', '信息提示'),
RegexValidator(r'正则表达式2', '信息提示')
],
或者
# 自定义验证规则
def mobile_validate(value):
mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
if not mobile_re.match(value):
raise ValidationError('手机号码格式错误')
validators=[mobile_validate,]
自定义函数的方式来编写验证规则。
Django为我们预留了钩子函数在字段验证时,当然这些函数都需要放在定义的表单类中。
# clean_字段名(),必须含有返回值,返回self.cleaned_data["字段名"]
def clean_user(self):
v = self.cleaned_data["user"]
print("验证用户名,当执行表单验证时执行", v)
if True:
raise ValidationError("用户已存在")
return v
def clean_age(self):
print("验证年龄,当执行表单验证时执行")
return self.cleaned_data["age"]
当想要验证多个字段是否同时满足条件时,则需要用到另外的一个钩子函数
def clean(self):
v = self.cleaned_data
user = v.get("user")
pwd = v.get("pwd")
if v != "666666" and pwd != "6666666":
# raise ValidationError("整体错误信息")
pass
print("所有字段都验证完成了", user, "\t", pwd)
# 必须返回 self.cleaned_data
return v
Field
required=True, 是否允许为空
widget=None, HTML插件
label=None, 用于生成Label标签或显示内容
initial=None, 初始值
help_text='', 帮助信息(在标签旁边显示)
error_messages=None, 错误信息 {'required': '不能为空', 'invalid': '格式错误'}
show_hidden_initial=False, 是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直)
validators=[], 自定义验证规则
localize=False, 是否支持本地化
disabled=False, 是否可以编辑
label_suffix=None Label内容后缀
CharField(Field)
max_length=None, 最大长度
min_length=None, 最小长度
strip=True 是否移除用户输入空白
IntegerField(Field)
max_value=None, 最大值
min_value=None, 最小值
DecimalField(IntegerField)
max_value=None, 最大值
min_value=None, 最小值
max_digits=None, 总长度
decimal_places=None, 小数位长度
BaseTemporalField(Field)
input_formats=None 时间格式化
DateField(BaseTemporalField) 格式:2015-09-01
TimeField(BaseTemporalField) 格式:11:12
DateTimeField(BaseTemporalField)格式:2015-09-01 11:12
RegexField(CharField)
regex, 自定制正则表达式
max_length=None, 最大长度
min_length=None, 最小长度
error_message=None, 忽略,错误信息使用 error_messages={'invalid': '...'}
EmailField(CharField)
FileField(Field)
allow_empty_file=False 是否允许空文件
ImageField(FileField)
...
注:需要PIL模块,pip3 install Pillow
以上两个字典使用时,需要注意两点:
- form表单中 enctype="multipart/form-data"
- view函数中 obj = MyForm(request.POST, request.FILES)
ChoiceField(Field)
...
choices=(), 选项,如:choices = ((0,'上海'),(1,'北京'),)
required=True, 是否必填
widget=None, 插件,默认select插件
label=None, Label内容
initial=None, 初始值
help_text='', 帮助提示
ModelChoiceField(ChoiceField)
... django.forms.models.ModelChoiceField
queryset, # 查询数据库中的数据
empty_label="---------", # 默认空显示内容
to_field_name=None, # HTML中value的值对应的字段
limit_choices_to=None # ModelForm中对queryset二次筛选
ModelMultipleChoiceField(ModelChoiceField)
django.forms.models.ModelMultipleChoiceField
TypedChoiceField(ChoiceField)
coerce = lambda val: val 对选中的值进行一次转换
empty_value= '' 空值的默认值
MultipleChoiceField(ChoiceField)
TypedMultipleChoiceField(MultipleChoiceField)
coerce = lambda val: val 对选中的每一个值进行一次转换
empty_value= '' 空值的默认值
ComboField(Field)
fields=() 使用多个验证,如下:即验证最大长度20,又验证邮箱格式
fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
MultiValueField(Field)
PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用
SplitDateTimeField(MultiValueField)
input_date_formats=None, 格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y']
input_time_formats=None 格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
FilePathField(ChoiceField) 文件选项,目录下文件显示在页面中
path, 文件夹路径
match=None, 正则匹配
recursive=False, 递归下面的文件夹
allow_files=True, 允许文件
allow_folders=False, 允许文件夹
required=True,
widget=None,
label=None,
initial=None,
help_text=''
GenericIPAddressField
protocol='both', both,ipv4,ipv6支持的IP格式
unpack_ipv4=False 解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用
SlugField(CharField) 数字,字母,下划线,减号(连字符)
UUIDField(CharField) uuid类型
常用字段及插件
CharField(Field)
IntegerField(Field)
DecimalField(IntegerField)
RegexField(CharField)
EmailField(CharField)
FileField(Field)
ImageField(FileField)
ChoiceField(Field)
MultipleChoiceField(ChoiceField)
GenericIPAddressField
TextInput(Input)
NumberInput(TextInput)
EmailInput(TextInput)
PasswordInput(TextInput)
HiddenInput(TextInput)
Textarea(Widget)
CheckboxInput
Select
SelectMultiple
RadioSelect
CheckboxSelectMultiple
FileInput
SelectDateWidget
关于多选与单选
# 常用选择插件
# 单radio,值为字符串
user = fields.CharField(
initial=2,
widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),))
)
# 单radio,值为字符串
user = fields.ChoiceField(
choices=((1, '上海'), (2, '北京'),),
initial=2,
widget=widgets.RadioSelect
)
# 单select,值为字符串
user = fields.CharField(
initial=2,
widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))
)
# 单select,值为字符串
user = fields.ChoiceField(
choices=((1, '上海'), (2, '北京'),),
initial=2,
widget=widgets.Select
)
# 多选select,值为列表
user = fields.MultipleChoiceField(
choices=((1,'上海'),(2,'北京'),),
initial=[1,],
widget=widgets.SelectMultiple
)
# 单checkbox
user = fields.CharField(
widget=widgets.CheckboxInput()
)
# 多选checkbox,值为列表
user = fields.MultipleChoiceField(
initial=[2, ],
choices=((1, '上海'), (2, '北京'),),
widget=widgets.CheckboxSelectMultiple
)
通过初始化方法实时更新选项
def __init__(self, *args, **kwargs):
# myform为类名
super(Myform,self).__init__(*args, **kwargs)
# self.fields['user'].widget.choices = ((1, '上海'), (2, '北京'),)
# 或
self.fields['user'].widget.choices = models.Classes.objects.all().value_list('id','caption')