1 全自动
优点: 不需要手动创建第三张表, orm查询简单
缺点: 第三张表无法扩展.当第三张表需要增加字段是无法操作.
# 全自动创建第三张表, 利用①语句经行创建. class Book(models.Model): title = models.CharField(max_length=32) price = models.DecimalField(max_digits=8,decimal_places=2) authors = models.ManyToManyField(to='Author') # ① class Author(models.Model): name = models.CharField(max_length=32)
2 手动创建
优点: 第三张表可以扩展
缺点: 查询不方便, 当连表查询的时候复杂
# 手动创建第三张关系表. class Book(models.Model): title = models.CharField(max_length=32) price = models.DecimalField(max_digits=8,decimal_places=2) class Author(models.Model): name = models.CharField(max_length=32) class Book2Author(models.Model): book = models.ForeignKey(to='Book') author = models.ForeignKey(to='Author') create_time = models.DateField(auto_now_add=True)
3 半自动
结合全自动与手动的优点
class Book(models.Model): title = models.CharField(max_length=32) price = models.DecimalField(max_digits=8,decimal_places=2) authors =models.ManyToManyField(to='Author',through='Book2Author',through_fields=('book','author')) # through 告诉django orm 书籍表和作者表的多对多关系是通过Book2Author来记录的 # through_fields 告诉django orm记录关系时用过Book2Author表中的book字段和author字段来#记录的 # 注意 这种情况下不支持 add, set, remove, clear等语法 class Author(models.Model): name = models.CharField(max_length=32) through_fields=('author', 'book') class Book2Author(models.Model): book = models.ForeignKey(to='Book') author = models.ForeignKey(to='Author') create_time = models.DateField(auto_now_add=True)
Django中forms组件
forms组件
针对于django前端的form表单进行处理.处理目的围绕三个方面:1,渲染页面. 2, 数据效验. 3 展示数据
2,forms组件基本用法
1, 首先调用forms组件
from django import forms
2, 自定义类
这个类是forms组件类,每个属性就是要校验的字段, 字段内部,有限制条件.如:max_length=8,最大长度为8.
EmailField()这个默认限定格式是邮件格式.
class MyForms(forms.Form): username = forms.CharField(max_length=8, min_length=3, ) password = forms.CharField(max_length=8, min_length=3) email = forms.EmailField()
限制条件的属性修改
限制条件是可以有其他修改,比如报错信息, 正则匹配, 控制标签属性等
# widget 控制标签属性和样式 widget=widgets.PasswordInput() # 控制标签属性 widget=widgets.PasswordInput(attrs={'class':'form-control c1 c2','username':'jason'}) # 正则匹配 from django.core.validators import RegexValidator phone = forms.CharField( validators = [RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '必须以数字159开头')] )
钩子函数(HOOK)
是组件类中的函数,一种是局部函数,一种是全局函数.
# 局部钩子(针对某一个字段做额外的校验) def clean_username(self): username = self.cleaned_data.get('username') if '111' in username: self.add_error('username', '什么鬼密码!重来') return username # 全局钩子(针对多个字段做额外的校验) def clean(self): password = self.cleaned_data.get('password') if '111' in password: self.add_error('password', '什么鬼密码') return self.cleaned_data
前端显示效果
调试组件类
在pycharm中python Console经行组件调试
from app01 import views # 导入调试模块 form_obj = views.MyForms({'username':'meKing', 'password': '15523', 'email':'[email protected]'}) # 实例化组件类,得到对象 form_obj.errors # 错误信息 # 结果: {} form_obj.is_valid() # 是否正确 # 结果: True form_obj.cleaned_data # 正确信息内容 # {'username': 'meKing', 'password': '15523', 'email': '[email protected]'}
forms组件api
def login(request): obj = MyForms() if request.method == 'POST': obj = MyForms(request.POST) return render(request, 'login.html', locals())
前端页面
<form action="" method="post" novalidate> // novalidate: 取消前端校验 {% for foo in obj %} <p> {{ foo.label }}:{{ foo }} <span>{{ foo.errors.0 }}span> // 显示报错信息 p> {% endfor %} <input type='submit'> form>
ps: 自定义类中所有字段都要出传值比对.
forms组件其他信息
常用字段与插件
创建Form类时,主要涉及到 【字段】 和 【插件】,字段用于对用户请求数据的验证,插件用于自动生成HTML;
initial
初始值,input框里面的初始值。
class LoginForm(forms.Form):
username = forms.CharField(
min_length=8,
label="用户名",
initial="张三" # 设置默认值
)
pwd = forms.CharField(min_length=6, label="密码")
error_messages
重写错误信息。
class LoginForm(forms.Form):
username = forms.CharField(
min_length=8,
label="用户名",
initial="张三",
error_messages={
"required": "不能为空",
"invalid": "格式错误",
"min_length": "用户名最短8位"
}
)
pwd = forms.CharField(min_length=6, label="密码")
password
class LoginForm(forms.Form):
...
pwd = forms.CharField(
min_length=6,
label="密码",
widget=forms.widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True)
)
radioSelect
单radio值为字符串
class LoginForm(forms.Form):
username = forms.CharField(
min_length=8,
label="用户名",
initial="张三",
error_messages={
"required": "不能为空",
"invalid": "格式错误",
"min_length": "用户名最短8位"
}
)
pwd = forms.CharField(min_length=6, label="密码")
gender = forms.fields.ChoiceField(
choices=((1, "男"), (2, "女"), (3, "保密")),
label="性别",
initial=3,
widget=forms.widgets.RadioSelect()
)
单选Select
class LoginForm(forms.Form):
...
hobby = forms.ChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
label="爱好",
initial=3,
widget=forms.widgets.Select()
)
多选Select
class LoginForm(forms.Form):
...
hobby = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
label="爱好",
initial=[1, 3],
widget=forms.widgets.SelectMultiple()
)
单选checkbox
class LoginForm(forms.Form):
...
keep = forms.ChoiceField(
label="是否记住密码",
initial="checked",
widget=forms.widgets.CheckboxInput()
)
多选checkbox
class LoginForm(forms.Form): ... hobby = forms.MultipleChoiceField( choices=((1, "篮球"), (2, "足球"), (3, "双色球"),), label="爱好", initial=[1, 3], widget=forms.widgets.CheckboxSelectMultiple() )
choice字段注意事项
在使用选择标签时,需要注意choices的选项可以配置从数据库中获取,但是由于是静态字段 获取的值无法实时更新,需要重写构造方法从而实现choice实时更新。
方式一 from django.forms import Form from django.forms import widgets from django.forms import fields class MyForm(Form): user = fields.ChoiceField( # choices=((1, '上海'), (2, '北京'),), initial=2, widget=widgets.Select ) def __init__(self, *args, **kwargs): super(MyForm,self).__init__(*args, **kwargs) # self.fields['user'].choices = ((1, '上海'), (2, '北京'),) # 或 self.fields['user'].choices = models.Classes.objects.all().values_list('id','caption') 方式二: from django import forms from django.forms import fields from django.forms import models as form_model class FInfo(forms.Form): authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all()) # 多选 # authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all()) # 单选
cookie与session
由于HTTP协议是无状态的, 无法记录用户状态.cookie与session是记录用户状态
cookie就是保存在客户端浏览器上的键值对. 工作原理:当你登陆成功之后 浏览器上会保存一些信息
下次再访问的时候 就会带着这些信息去访问服务端 服务端通过这些信息来识别出你的身份, cookie虽然是写在客户端浏览器上的 但是是服务端设置的, 浏览器可以选择不服从命令 禁止写cookie.
设置cookie利用的就是HttpResponse对象
obj1.set_cookie('k1','v1')
获取cookie
request.COOKIE.get()
删除cookie
obj1.delete_cookie("k1")
设置超时时间
max_age=None, 超时时间
expires=None, 超时时间(IE requires expires, so set it if hasn't been already.)
登陆功能
设置session
request.session['name'] = 'jason'
"""
上面这一句话发生了三件事
1.django 内部自动生成一个随机字符串
2.将随机字符串和你要保存的数据 写入django_session表中(现在内存中生成一个缓存记录 等到经过中间件的时候才会执行)
3.将产生的随机字符串发送给浏览器写入cookie
sessionid:随机字符串
"""
获取session
request.session.get('name')
"""
上面这一句话发生了三件事
1.django内部会自动从请求信息中获取到随机字符串
2.拿着随机字符串去django_session表中比对
3.一旦对应上了就将对应的数据解析出来放到request.session中
"""
django session默认的超时时间是14天
django_session表中的一条记录针对一个浏览器
删除当前会话的所有Session数据
request.session.delete() # 删除的是浏览器的sessionid信息
删除当前的会话数据并删除会话的Cookie。
request.session.flush() # 将浏览器和服务端全部删除
这用于确保前面的会话数据不可以再次被用户的浏览器访问
例如,django.contrib.auth.logout() 函数中就会调用它。
设置会话Session和Cookie的超时时间
request.session.set_expiry(value)
-
如果value是个整数,session会在些秒数后失效。
-
如果value是个datatime或timedelta,session就会在这个时间后失效。
-
如果value是0,用户关闭浏览器session就会失效。
-
如果value是None,session会依赖全局session失效策略
-
总结:你在后期可以将一些数据保存到session表中,保存的数据 可以在后端任意位置获取到