一。多对多建表关系之手动添加。

  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的更多相关文章

  1. Django-多对多建表与Form表单

    一.多对多建表的三种创建方式: 1.全自动型:(一般情况下使用) class Book(models.Model): title = models.CharField(max_length=32) a ...

  2. django之表多对多建立方式、form组件、钩子函数 08

    目录 多对多三种创建方式 1.全自动(用ManyToManyField创建第三张表) 2.纯手写 3.半自动 form组件 引入 form组件的使用 forms组件渲染标签 form表单展示信息 fo ...

  3. Django多对多关系建立及Form组件

    目录 Django多对多关系 1.创建方式一全自动 2.创建方式二纯手撸 3.半自动(推荐使用) forms校验组件 使用forms组件实现注册功能 form常用字段和插件 数据校验 钩子函数 HOO ...

  4. hibernate建表多对多建表

    Student.java package cn.itcast.hiberate.sh.domain; import java.util.Set; public class Student { priv ...

  5. Mysql 建表时,日期时间类型选择

    mysql(5.5)所支持的日期时间类型有:DATETIME. TIMESTAMP.DATE.TIME.YEAR. 几种类型比较如下: 日期时间类型 占用空间 日期格式 最小值 最大值 零值表示  D ...

  6. MySQL建表时,日期时间类型选择

    MySQL(5.5)所支持的日期时间类型有:DATETIME. TIMESTAMP.DATE.TIME.YEAR. 几种类型比较如下: 日期时间类型 占用空间 日期格式 最小值 最大值 零值表示  D ...

  7. powerDesigner建表时选择不同数据库类型

    l  使用powerDesigner创建表模型的时候可选择数据库类型 如图设置为mysql:

  8. Django框架(十)--ORM多对多关联关系三种创建方式、form组件

    多对多的三种创建方式 1.全自动(就是平常我们创建表多对多关系的方式) class Book(models.Model): title = models.CharField(max_length=32 ...

  9. 多对多关系表的创建方式、forms组件

    目录 多对多关系表的三种创建方式 1.全自动,Django自动创建 2.纯手撸 3.半自动(推荐使用) forms组件 小例子 forms组件 校验器 钩子函数 局部钩子 全局钩子 forms组件常用 ...

随机推荐

  1. 2019-2020-1 20199305《Linux内核原理与分析》第一周作业

    进入Linux的世界 1.何为Linux? Linux是一个操作系统. 2.Linux的由来 芬兰赫尔辛基大学的研究生 Linus Torvalds接触Unix时认为其费用不友好,决定自己开发一个操作 ...

  2. 史上最全的各种C++ STL容器全解析

    史上最全的C++ STL 容器大礼包 为什么\(C++\)比\(C\)更受人欢迎呢?除了\(C++\) 的编译令人感到更舒适,\(C++\)的标准模板库(\(STL\))也占了很重要的原因.当你还在用 ...

  3. Java内存中的常量池

    1,java内存模型简介 <深入理解java虚拟机>里将java内存分为如下五个模块: 堆-堆是所有线程共享的,主要用来存储对象. 其中,堆可分为:新生代和老年代两块区域.使用NewRat ...

  4. STL pair类型的介绍

    pair标准库类型它定义在头文件utility中. 一个pair保存两个数据成员.类似容器,pair是一个用来生成特定类型的模板.当创建一个pair时,我们必须提供两个类型名,pair的数据成员将具有 ...

  5. Note | 用Hugo搭建博客并部署到GitHub Pages

    目录 1. 本地搭建 1.1 安装Hugo 1.2 创建站点 1.3 新建页面和文章 1.4 使用主题 1.5 修改配置文件 1.6 预览 2. 部署 之前担心过现有博客平台(如博客园,CSDN)突然 ...

  6. C#开发BIMFACE系列29 服务端API之获取模型数据14:获取图纸列表

    系列目录     [已更新最新开发文章,点击查看详细] 一个三维模型中可能包含对应多张二维图纸列表,本篇主要介绍如何获取模型文件对应的图纸列表. 请求地址:GET https://api.bimfac ...

  7. 从零开始的微信小程序入门教程(一)

    之前说要和同事一起开发个微信小程序项目,现在也在界面设计,功能定位等需求上开始实施了.所以在还未正式写项目前,打算在空闲时间学习下小程序.本意是在学习过程中结合实践整理出一个较为入门且不是很厚的教程, ...

  8. Swiper实现轮播图效果

    为了实现轮播图(carousel)效果或左右滑动显示不同的内容,我们采用Swiper来实现. 需要引入swiper.min.css和swiper.min.js,文件可从https://github.c ...

  9. H5混合应用之webview元素定位工具

    一.工具选择 webview元素定位有三种方式: 使用driver.page_source方法,将获取到的页面内容写入到一个html文件中,然后使用浏览器打开html文件,使用F12调试用具进行元素定 ...

  10. 点云3D 目标检测

    点云 点云是雷达采集到的信息. 关于点云基本介绍参考https://zhuanlan.zhihu.com/p/22581673 ros中的点云消息结构:http://docs.ros.org/jade ...