目录
多对多三种建表方式
-
全自动
class Book(models.Model): title = models.CharField(max_length=32) # 多对多关系字段 authors = models.ManyToManyField(to='Authors') class Authors(models.Model): name = models.CharField(max_length=32)
优点:
- 自动建表,由orm自动创建
- 内置了add/remove/set/clear四个操作
缺点:
- 自动创建的第三张关系表无法扩展和修改字段,表的扩展性较差
-
纯手动
class Book(models.Model): title = models.CharField(max_length=32) class Authors(models.Model): name = models.CharField(max_length=32) class Book2Authors(models.Model): book = models.ForeignKey(to="Book") author = models.ForeignKey(to="Authors") create_time = models.DateField(auto_now_add = True)
优点:
- 第三张表中所有字段都可以自己定义
缺点:
- 不再支持跨表查询,不再有正反向的概念
- 没有了add/remove/set/clear四个操作
-
半自动
class Book(models.Model): title = models.CharField(max_length=32) # 多对多关系字段 authors = models.ManyToManyField( to='Authors', through='Book2Author', through_fields=("book","authors") ) class Authors(models.Model): name = models.CharField(max_length=32) # 多对多关系字段 等价 books = models.ManyToManyField( to='Book', through='Book2Author', through_fields=("authors","book") ) class Book2Author(models.Model): book = models.ForeignKey(to='Book') authors = models.ForeignKey(to='Authors') ''' 当你的ManyToManyField只有一个参数to的情况下,orm会自动帮你创建第三张表; 如果你加了through和through_fileds那么orm就不会自动帮你你创建,但是会在内部帮你维护关系,让你能够继续使用orm的跨表查询 '''
优点:
- 可以添加修改第三张关系表中的字段
- 支持orm跨表查询
缺点:
- 不支持add/remove/set/clear四个操作
FORM组件
主要功能:
- 生成可用的HTML标签
- 对用户提交的数据进行校验
- 保留上次输入的内容
前提
from django import forms
#需要先定义一个类
class MyForm(forms.Form):
username = forms.CharField(max_length=8,min_length=3)
password = forms.CharField(max_length=8,min_length=3)
# email字段 必须是邮箱格式
email = forms.EmailField()
前端校验数据
# 实例化类
form_obj = views.MyForm({'username':'jason','password':'12','email':'123'})
# 查看校验的数据是否合法
form_obj.is_valid()
# 查看不符合规则的字段及错误的理由
form_obj.errors
# 查看符合规则的字段的数据
form_obj.cleaned_data
# 传值数量
'''
因为是由类的字段向实例化对象字段的映射,所以不能少传;但是多传的话,多传的字段不会进行校验
'''
渲染标签
forms组件只会帮你渲染获取用户输入的标签,不会渲染提交按钮
-
方式一:封装程度太高,不推荐使用,可以用在本地测试
{{ form_obj.as_p }} <!--自动渲染所有input框 --> {{ form_obj.as_ul }} {{ form_obj.as_table }}
-
方式二:不推荐使用
{{ form_obj.username.label }}{{ form_obj.username }} {{ form_obj.username.label }}{{ form_obj.password }} {{ form_obj.username.label }}{{ form_obj.email }}
-
方式三:推荐使用
{% for form in form_obj %} <!--form 等价于你方式2中的对象点字段名--> <p>{{ form.label }}{{ form }}</p> {% endfor %}
展示信息
<form action="" method="post" novalidate>
{% for forms in form_obj %}
<p>
{{ forms.label }}{{ forms }}
<span>{{ forms.errors.0 }}</span>
</p> <!--form 等价于你方式2中的对象点字段名-->
{% endfor %}
<input type="submit">
</form>
后端校验
前端校验可有可无,后端校验必不可少
<!--告诉浏览器不做前端校验-->
<form action="" method="post" novalidate>
内置校验器
from django.core.validators import RegexValidator
#validators作为字段参数
validators=[
RegexValidator(r'^[0-9]+$', '请输入数字'),
RegexValidator(r'^159[0-9]+$', '数字必须以159开头'),
]
自定义校验器
import re
from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.exceptions import ValidationError
# 自定义验证规则
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('手机号码格式错误')
class PublishForm(Form):
title = fields.CharField(max_length=20,
min_length=5,
error_messages={'required': '标题不能为空',
'min_length': '标题最少为5个字符',
'max_length': '标题最多为20个字符'},
widget=widgets.TextInput(
attrs={'class': "form-control",
'placeholder': '标题5-20个字符'}
))
# 使用自定义验证规则
phone = fields.CharField(validators=[mobile_validate, ],
error_messages={'required': '手机不能为空'},
widget=widgets.TextInput(
attrs={'class': "form-control",
'placeholder': u'手机号码'}
))
email = fields.EmailField(required=False,
error_messages={
'required': u'邮箱不能为空',
'invalid': u'邮箱格式错误'
},
widget=widgets.TextInput(
attrs={'class': "form-control",
'placeholder': u'邮箱'
}
))
HOOK方法
class LoginForm(forms.Form):
username = forms.CharField(
min_length=8,
label="用户名",
initial="张三",
error_messages={
"required": "不能为空",
"invalid": "格式错误",
"min_length": "用户名最短8位"
},
widget=forms.widgets.TextInput(attrs={"class": "form-control"})
)
...
# 定义局部钩子,用来校验username字段
def clean_username(self):
value = self.cleaned_data.get("username")
if "666" in value:
raise ValidationError("光喊666是不行的")
else:
return value
class LoginForm(forms.Form):
...
password = forms.CharField(
min_length=6,
label="密码",
widget=forms.widgets.PasswordInput(
attrs={'class': 'form-control'},
render_value=True)
)
re_password = forms.CharField(
min_length=6,
label="确认密码",
widget=forms.widgets.PasswordInput(
attrs={'class': 'form-control'},
render_value=True)
)
...
# 定义全局的钩子,用来校验密码和确认密码字段是否相同
def clean(self):
password_value = self.cleaned_data.get('password')
re_password_value = self.cleaned_data.get('re_password')
if password_value == re_password_value:
return self.cleaned_data
else:
self.add_error('re_password', '两次密码不一致')
raise ValidationError('两次密码不一致')
常用字段和插件(了解即可)
#默认值
initial='默认值'
#重写错误信息
error_messages={
'requeire':'不能为空',
'invalid':'格式错误',
'min_length':'用户名最短8位',
}
#修改标签类
widget = forms.widgets.PasswordInput(attrs={'class':'c1 c2'})