day58_9_24多对多建表手动,form组件(判断类型),cookies和session
一。多对多建表关系之手动添加。
1。全自动
像之前讲过的一样,我们可以通过manytomanyField的字段来建立多对多关系:
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)
优点:可以任意添加扩展的字段。
缺点:不能使用orm中的外键查询。
3.半自动
在创建第三张表的情况下,创建1,2张表的manytomany到该表中
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字段来记录的 class Author(models.Model):
name = models.CharField(max_length=32)
# books = models.ManyToManyField
(to='Book', through='Book2Author', 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)
manytomany字段中的各个参数的意义是:
to:关联的那张表。
through:绑定的第三张表。
throuth_fields:记录关系时用到的字段,前面时本表查询他表时经过的字段
这种方法定义的表不适合使用以下查询或设置函数:
add set remove chear。
二。forms组件。
在前端输入用户名和密码时,会有提示你的密码过于短等,这些都是forms的作用,用来限制你输入的内容并报错,我们可以手动实现一个简单的版本:
def login(request):
errors = {'username':'','password':''}
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
if '不好的' in username:
errors['username'] = '不符合名字'
if len(password) < 3:
errors['password'] = '太短了'
return render(request,'login.html',locals())
视图层
<form action="" method="post">
<p>username:<input type="text" name="username"><span>{{ errors.username }}</span></p>
<p>password:<input type="password" name="password"><span>{{ errors.password }}</span></p>
<p><input type="submit" value="提交"></p> </form>
模板层
刚刚的代码种会出现以下步骤:
1.前端页面搭建。
2。将数据传输到后端做校验。
3.展示错误信息。
而使用forms组件会出现以下步骤:
1.渲染前端页面
2.校验数据是否合法
3.展示错误信息
1.基本的forms用法:
这个组件需要导入模块,语法和orm差不多:
from django import forms
class LoginForm(forms.Form):
username = forms.CharField(max_length=8,min_length=3) # 用户名最长八位最短三位
password = forms.CharField(max_length=8,min_length=5) # 密码最长八位最短五位
email = forms.EmailField() # email必须是邮箱格式
在测试这些代码时,可以在python中的终端中测试,但是需要先导入相关模块,本地路劲是当前项目的路径。
1.如果需要校验数据,就需要以字典 的方式传递给自定义的类,它会产生对象,通过该对象的一些方法就可以实现检测:
form_obj = views.LoginForm({'username':'jason','password':'','email':''})
2.使用is_valid()方法就可以判断该字典中的数据是否都符合要求。
form_obj.is_valid() # 只有所有的数据都符合要求 才会是True
False
3.查看错误原因,当使用errors时,会返回一个字典加列表的数据,其中就有该数据的错误原因:
form_obj.errors
{'password': ['Ensure this value has at least 5 characters (it has 3).'],
'email': ['Enter a valid email address.']
}
4.如何查看通过校验的数据:cleaned_data方法
form_obj.cleaned_data
{'username': 'jason'}
在使用forms字段时:
1.当输入的字典中有其他自定义类中的数据时,不会出错,forms也不会处理。
2.当输入的字典中没有自定义的类中的一些字段时,会出错,is_valid()会时false。
3。具体流程就是将字典中的字段和类中的字段一一匹配,再比较限定条件。
2.渲染页面的方法:
再页面中,可以直接将该类生成的对象返回给前端,前端段可以直接进行渲染。
1.:过度封装的渲染方法:
第一种渲染页面的方式(封装程度太高 一般只用于本地测试 通常不适用):
{{ form_obj.as_p }}
{{ form_obj.as_ul }}
{{ form_obj.as_table }}
as_p就是将结果变成p格式的
as_ul就是变成列表形式的。
as_table就是普通格式的。
2.扩展性较高的方法,
这种方法书写麻烦,每个对象中点出其中的label和其中的名字。
<p>{{ form_obj.username.label }}{{ form_obj.username }}</p>
<p>{{ form_obj.password.label }}{{ form_obj.password }}</p>
<p>{{ form_obj.email.label }}{{ form_obj.email }}</p>
3.可批量的渲染:
将该对象for循环可以得出其中的所有字段信息。
{% for foo in form_obj %}
<p>{{ foo.label }}{{ foo }}
<span>{{ foo.errors.0 }}</span>
</p>
{% endfor %}
3.错误信息展示。
使用foo.errors可以将错误信息以列表的形式展出,但是会改变原来的板块,所以需要再后面.0取出其中的本来的错误信息。
提交按钮不会帮你添加,需要手动添加。
当form中的label没有指定的时候,就是该字段名的首字母大写。label表示的是这个字段代表的内容名字
在前端,这些限制已经有了作用,但是这些限制在爬虫的对抗上没有什么用,所以需要在前端和 后端都加上限制。为了取消前端的限制,测试后端限制,需要给表单加上关键字novalidate
在普通字段中,需要显示中文的错误提示,需要对其error_messages进行设置。其中的值代表的是:
1.max_length,最大的。。这些都是在定义字段是自己定义的。
2.required代表为空是报的错。
3.invalid代表邮箱的格式是否正确。
例子:
password = forms.CharField(max_length=8,min_length=5,label='密码',error_messages={
'max_length':'密码最大八位',
'min_length':'密码最小五位',
'required':'密码不能为空'
},)
在字段中也有可以使用正则匹配的限制条件,关键字是RegexValidator,后面是错误信息:
class MyForm(Form):
user = fields.CharField(
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'邮箱'}))
自定义函数校验
三。钩子函数。
当你的本来字段中的函数限制校验通过后,还需要进行校验是,就需要通过钩子函数。
改函数需要返回对应的字段
钩子函数的定义是在自定义类中定义,类中会将你定义的字段钱加clean_封装好,定义的时候有两种报错方式:
def clean_username(self):
username = self.cleaned_data.get('username')
if '' in username:
# raise ValidationError('奥术大师就卡的凯撒就肯定会')
self.add_error('username','光喊666是不行的 你得自己上')
return username
一种是raise,一种是add_error。
还有一种是全局钩子,可以跨字段进行校验:
返回值是数据字典。
def clean(self):
password = self.cleaned_data.get('password')
confirm_password = self.cleaned_data.get('confirm_password')
if not password == confirm_password:
self.add_error('confirm_password','两次密码不一致')
return self.cleaned_data
四。其他字段的操作方式。
在字段中,有以下参数可以设置:
required 是否必填
label 注释信息
error_messages 报错信息
initial 默认值
widget 控制标签属性和样式(密码格式,文本格式等)
关于widget关键字,还可以用来操作class,也就是添加类:
widget=widgets.PasswordInput(
attrs={'class':'form-control c1 c2','username':'jason'})
其他类型字段:
1.radioSelect
gender = forms.ChoiceField(
choices=((1, "男"), (2, "女"), (3, "保密")),
label="性别",
initial=3,
widget=forms.widgets.RadioSelect()
)
2.单选Select
hobby = forms.ChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=3,
widget=forms.widgets.Select()
)
3.多选Select
hobby1 = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=[1, 3],
widget=forms.widgets.SelectMultiple()
)
4.单选checkbox
keep = forms.ChoiceField(
label="是否记住密码",
initial="checked",
widget=forms.widgets.CheckboxInput()
)
5.多选checkbox
hobby2 = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=[1, 3],
widget=forms.widgets.CheckboxSelectMultiple()
)
以上的代码中initial是其默认选择项,widget代表其中的真实数据。
is_valid原理:
首先先获取所有的字段的信息,放入全局的cleaned_data中,再调用全局的校验方法,进行校验,有错就会报错。
五。cookies和session
由于http协议是无状态的,法记录用户状态 。
1.cookies
cookie就是保存在客户端浏览器上的键值对。
工作原理:当你登陆成功之后 浏览器上会保存一些信息。下次再访问的时候 就会带着这些信息去访问服务端 服务端通过这些信息来识别出你的身份。
cookie虽然是写在客户端浏览器上的 但是是服务端设置的。浏览器可以选择不服从命令 禁止写cookie。
2.session
session就是保存在服务器上的键值对。
session虽然是保存在服务器上的键值对。但是它是依赖于cookie工作的。
服务端返回给浏览器一个随机的字符串。浏览器以键值对的形式保存。
sessionid就是一个随机字符串。浏览器在访问服务端的时候 就会将随机字符串携带上。后端获取随机串与后端的记录的做比对。如:
随机字符串1:数据1。
随机字符串2:数据2
查看Cookie
我们使用Chrome浏览器,打开开发者工具。
六。cookies的获取和删除。
cookies的获取可以从COOKIES中获取。
设置cookie利用的就是HttpResponse对象
obj1.set_cookie('k1','v1')
获取cookie
request.COOKIE.get()
request.COOKIES['key']
request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
而再设置cookies中是以键值对的方式设置。设置的对象就是HttpResponse对象,最后再返回这个对象即可
obj.set_cookie('name','jason',max_age=30)
return obj
参数:
- default: 默认值
- salt: 加密盐
- max_age: 后台控制过期时间
其中还有删除方法:
def logout(request):
rep = redirect("/login/")
rep.delete_cookie("user") # 删除用户浏览器上之前设置的usercookie值
return rep
def check_login(func):
@wraps(func)
def inner(request, *args, **kwargs):
next_url = request.get_full_path()
if request.get_signed_cookie("login", salt="SSS", default=None) == "yes":
# 已经登录的用户...
return func(request, *args, **kwargs)
else:
# 没有登录的用户,跳转刚到登录页面
return redirect("/login/?next={}".format(next_url))
return inner def login(request):
if request.method == "POST":
username = request.POST.get("username")
passwd = request.POST.get("password")
if username == "xxx" and passwd == "dashabi":
next_url = request.GET.get("next")
if next_url and next_url != "/logout/":
response = redirect(next_url)
else:
response = redirect("/class_list/")
response.set_signed_cookie("login", "yes", salt="SSS")
return response
return render(request, "login.html") cookie版登录
cookies登录校验
七。session的删除和设置。
session设置需要打开数据库,首先生成数据库文件:
# 获取、设置、删除Session中数据
request.session['k1']
request.session.get('k1',None)
request.session['k1'] = 123
request.session.setdefault('k1',123) # 存在则不设置
del request.session['k1']
而设置session经过了三件是,也就是session['key']= 'val'
1.django 内部自动生成一个随机字符串
2.将随机字符串和你要保存的数据 写入django_session表中(现在内存中生成一个缓存记录 等到经过中间件的时候才会执行)
3.将产生的随机字符串发送给浏览器写入cookie
获取session也会发生这几件事:
1.django内部会自动从请求信息中获取到随机字符串
2.拿着随机字符串去django_session表中比对
3.一旦对应上了就将对应的数据解析出来放到request.session中
session中的记录默认是保存14tian,过期后数据不会消失,但是取值取不到。
当单个session设置了多个值时,值会保存到一个sessionid中,可以正常取值。
django_session表中的一条记录针对一个浏览器。
删除信息。
删除信息有两种:
# 删除当前会话的所有Session数据
request.session.delete()
# 删除当前的会话数据并删除会话的Cookie。
request.session.flush()
这用于确保前面的会话数据不可以再次被用户的浏览器访问
例如,django.contrib.auth.logout() 函数中就会调用它。
delete是将浏览器中的session删除。
而flush,删除的是数据库中的session和浏览器中的。
session也可以设置超时时间:
# 设置会话Session和Cookie的超时时间
request.session.set_expiry(value)
* 如果value是个整数,session会在些秒数后失效。
* 如果value是个datatime或timedelta,session就会在这个时间后失效。
* 如果value是0,用户关闭浏览器session就会失效。
* 如果value是None,session会依赖全局session失效策略。
过期后数据不会消失,但是取值取不到。
在后期可以将一些数据保存到session表中,保存的数据 可以在后端任意位置获取到。
day58_9_24多对多建表手动,form组件(判断类型),cookies和session的更多相关文章
- Django-多对多建表与Form表单
一.多对多建表的三种创建方式: 1.全自动型:(一般情况下使用) class Book(models.Model): title = models.CharField(max_length=32) a ...
- django之表多对多建立方式、form组件、钩子函数 08
目录 多对多三种创建方式 1.全自动(用ManyToManyField创建第三张表) 2.纯手写 3.半自动 form组件 引入 form组件的使用 forms组件渲染标签 form表单展示信息 fo ...
- Django多对多关系建立及Form组件
目录 Django多对多关系 1.创建方式一全自动 2.创建方式二纯手撸 3.半自动(推荐使用) forms校验组件 使用forms组件实现注册功能 form常用字段和插件 数据校验 钩子函数 HOO ...
- hibernate建表多对多建表
Student.java package cn.itcast.hiberate.sh.domain; import java.util.Set; public class Student { priv ...
- Mysql 建表时,日期时间类型选择
mysql(5.5)所支持的日期时间类型有:DATETIME. TIMESTAMP.DATE.TIME.YEAR. 几种类型比较如下: 日期时间类型 占用空间 日期格式 最小值 最大值 零值表示 D ...
- MySQL建表时,日期时间类型选择
MySQL(5.5)所支持的日期时间类型有:DATETIME. TIMESTAMP.DATE.TIME.YEAR. 几种类型比较如下: 日期时间类型 占用空间 日期格式 最小值 最大值 零值表示 D ...
- powerDesigner建表时选择不同数据库类型
l 使用powerDesigner创建表模型的时候可选择数据库类型 如图设置为mysql:
- Django框架(十)--ORM多对多关联关系三种创建方式、form组件
多对多的三种创建方式 1.全自动(就是平常我们创建表多对多关系的方式) class Book(models.Model): title = models.CharField(max_length=32 ...
- 多对多关系表的创建方式、forms组件
目录 多对多关系表的三种创建方式 1.全自动,Django自动创建 2.纯手撸 3.半自动(推荐使用) forms组件 小例子 forms组件 校验器 钩子函数 局部钩子 全局钩子 forms组件常用 ...
随机推荐
- configparser读取配置文件时的相对路径问题
学习接口测试时,当我把配置文件xx.config和读取配置文件的模块read_config.py放在项目下的同一个包config里时,只需传入文件名xx.config即可实现对配置文件的读取. 但是当 ...
- Vue 组件通信的多种方式(props、$ref、$emit、$attr、 $listeners)
prop和$ref之间的区别: prop 着重于数据的传递,它并不能调用子组件里的属性和方法.像创建文章组件时,自定义标题和内容这样的使用场景,最适合使用prop. $ref 着重于索引,主要用来调用 ...
- [CF1082D]Maximum Diameter Graph
题目描述 Description Graph constructive problems are back! This time the graph you are asked to build sh ...
- Codeforces Round #602 (Div. 2, based on Technocup 2020 Elimination Round 3) F2. Wrong Answer on test 233 (Hard Version) dp 数学
F2. Wrong Answer on test 233 (Hard Version) Your program fails again. This time it gets "Wrong ...
- vb.net 带有一个参数的线程
For Each _row As DataGridViewRow In datagridview.Rows 'searchRecords_refreshRow(_row) ' 上面以前,直接运行函数, ...
- linux常用命令指南——查找文件我最强:find
2.3.2 查找文件我最强:find 2.3.2.1 find查找常用命令示例 find / -name 'wfy.txt' # 从根目录下开始查找文件wfy.txt find . -name '*f ...
- 【nginx启动报错】重启服务器之后nginx启动错
错误信息: # ./nginx nginx: [emerg] open() "/var/run/nginx/nginx.pid" failed (2: No such file ...
- Java设计模式:Singleton(单例)模式
概念定义 Singleton(单例)模式是指在程序运行期间, 某些类只实例化一次,创建一个全局唯一对象.因此,单例类只能有一个实例,且必须自己创建自己的这个唯一实例,并对外提供访问该实例的方式. 单例 ...
- oracle多表关联update
日常的开发中一般都是写的单表update语句,很少写多表关联的update. 不同于SQL Server,在Oracle中,update的多表连接更新和select的多表连接查询在使用的方法上存在较大 ...
- php使用inotify扩展监控文件或目录的变化
一.安装inotify扩展 1.下载inotify扩展源码 https://pecl.php.net/package/inotify 对于php7以上版本,请下载 inotify-2.0.0.tgz. ...