day57总结

表的多对多关系的三种创建方式

查阅框架文档及百度案例:

基于人家已经写好的功能修改

  1. 先看配置参数
  2. 前期就是猜, 改几个参数看结果, 看猜的是否对
  3. 整体修改

全自动创建

class Books(models.Model):
    title = models.CharField(max_length=32)
    authors = models.ManyToManyField(to='Authors')


class Authors(models.Model):
    name = models.CharField(max_length=32)

优点: 1. 不需要手动操作关系表, 全部由orm自动创建; 2. 并且内置了四个操作关系表的方法(add, remove, set, clear)

缺点: 自动创建的关系表无法扩展和修改字段

纯手撸(了解)

class Books(models.Model):
    title = models.CharField(max_length=32)


class Authors(models.Model):
    name = models.CharField(max_length=32)


class BooksToAuthors(models.Model):
    book = models.ForeignKey(to='Books')
    author = models.ForeignKey(to='Authors')
    create_time = models.DateField(auto_created=True)  # 关系表中的扩展字段

优点: 关系表中的字段可以自己定义

缺点: 不再支持orm跨表查询以及四个操作关系表的方法(add, remove, set, clear)

半自动(推荐使用)

class Books(models.Model):
    title = models.CharField(max_length=32)

    '''
    1. 添加through和through_field参数, ManyToManyField就不会再自动创建关系表
    2. through设置关系表通过自定义表建立, 
    3. through_fields设置通过自定义表中的哪两个字段建立多对多关系
    4. 在哪张表中声明, 该表在自定义表中对应的字段就放在前面
    '''
    authors = models.ManyToManyField(to='Authors', through='BooksToAuthors', through_fields=('book', 'author'))


class Authors(models.Model):
    name = models.CharField(max_length=32)
    # books = models.ManyToManyField(to='Books', through='BooksToAuthors', through_fields=('author', 'book'))


class BooksToAuthors(models.Model):
    book = models.ForeignKey(to='Books')
    author = models.ForeignKey(to='Authors')
    create_time = models.DateField(auto_created=True)  # 关系表中的扩展字段

优点: 可以添加和修改关系表中的字段, 并且支持跨表查询

缺点: 不支持四个操作关系表的方法(add, remove, clear, set)

forms组件简介

forms组件的作用

  1. 渲染标签--- 手动书写html代码获取用户输入
  2. 校验数据---将数据传递给后端做数据校验
  3. 展示信息---如果数据有错误, 展示错误信息
# 简易注册信息校验示例
def register(request):
    errors_dic = {'username': '', 'password': ''}
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        if 'jinpingmei' in username:
            errors_dic['username'] = '不符合社会主义核心价值观'
        if len(password) <= 3:
            errors_dic['password'] = '密码不能少于4位'

    return render(request, 'register.html', locals())


'''
<form action="" method="post">
    <p>
        username: <input type="text" name="username">
        <span style="color: red;">{{ errors_dic.username }}</span>
    </p>
    <p>
        password: <input type="text" name="password">
        <span style="color: red;">{{ errors_dic.password }}</span>
    </p>
    <input type="submit">
</form>
'''

forms组件校验数据

  • 使用forms组件, 先导入模块: from django import forms

  • 在views.py中自定义MyForm类

    class MyForm(forms.Form):
        username = forms.CharField(max_length=8, min_length=3)  # username字段最多8位, 最少3位
        password = forms.CharField(max_length=8, min_length=3)
        email = forms.EmailField()  # email字段必须是邮箱格式
  • 测试代码的第二种方式: Python Console-->Django Console

    from app01 import views
    
    form_obj = views.MyForm({'username': 'jason', 'password': '12', 'email': '456'})  # 实例化时参数为字典形式
    form_obj.is_valid()  # False, 所有数据全部符合校验规则才为True
    form_obj.errors  # {'password': ..., 'email': ['Enter a valid email address.']}, 查看不符合规则的字段及错误信息
    form_obj.cleaned_data  # {'username': 'jason'}, 查看符合校验规则的数据
    
    '''
    1. forms组件的类中定义的字段默认都必须传值, 不能少传
    2. forms组件只会校验类中定义的字段, 如果传入其他字段, 不会有任何影响
    '''

forms组件渲染标签

forms组件只会渲染获取用户输入的标签, 不会渲染提交按钮

def index(request):
    # 渲染标签, 需先生成一个空的MyForm类的对象
    form_obj = MyForm()
    return render(request, 'index.html', locals())

forms组件渲染标签方式一

封装程度高, 难扩展, 只用于本地测试

'''
{{ form_obj.as_p }}  # 会自动渲染input框和label标签, 由p标签包裹
{{ form_obj.as_ul }}  # ..., 由ul标签包裹
{{ form_obj.as_table }}  # ..., 渲染到一行上
'''

forms组件渲染标签方式二

组合: form_field_obj为form_obj的属性

class MyForm(forms.Form):
    username = forms.CharField(max_length=8, min_length=3, label='用户名') 
    password = forms.CharField(max_length=8, min_length=3, label='密码')
    email = forms.EmailField(label='邮箱')  
'''
{% for form_field_obj in form_obj %}
    <p>{{ form_field_obj.label }}{{ form_field_obj }}</p>
{% endfor %}
'''

form组件展示信息

数据的校验通常情况前后端都有, 但前端的校验弱不禁风, 所以后端的校验必须要有, 且需非常全面

浏览器识别到使用forms组件时会自动使用前端的校验功能

def index(request):
    # 渲染标签, 需先生成一个空的MyForm类的对象
    form_obj = MyForm()

    if request.method == 'POST':  # 前端识别到后端使用forms组件时会自动先进行一轮校验
        form_obj = MyForm(request.POST)
        if form_obj.is_valid():
            return HttpResponse('数据全部OK')
        else:
            print(form_obj.errors)
    return render(request, 'index.html', locals())

设置前端不做校验: <form action="" method="post" novalidate>

def index(request):
    # 渲染标签, 需先生成一个空的MyForm类的对象
    form_obj = MyForm()  # 空对象渲染输入框

    if request.method == 'POST':
        form_obj = MyForm(request.POST)  # form_obj实际渲染用户数据, 两个对象的名称需一致
        if form_obj.is_valid():
            return HttpResponse('数据全部OK')
        
    return render(request, 'index.html', locals())


'''
<form action="" method="post" novalidate>
    {% for form_field_obj in form_obj %}
        <p> 
            {{ form_field_obj.label }}{{ form_field_obj }}  # label默认获取到的是类中字段名的首字母大写形式
            <span>{{ form_field_obj.errors.0}}</span>  # 前端获取报错信息固定写法
        </p>

    {% endfor %}
    <input type="submit">
</form>
'''


class MyForm(forms.Form):
    username = forms.CharField(
        max_length=8,
        min_length=3,
        label='用户名',
        error_messages={  # 自定义显示报错信息
            'max_length': '用户名最长八位',
            'min_length': '用户名最短3位',
            'required': '用户名不能为空'
        }
    )
    ...
    email = forms.EmailField(
        label='邮箱',
        error_messages={
            'required': '邮箱不能为空',
            'invalid': '邮箱格式错误'
        }
    )

forms组件自定义校验

正则校验

'''
from django.core.validators import RegexValidator


class MyForm(forms.Form):
    username = forms.CharField(
        ...
        ...
        validators=[
            RegexValidator(r'[0-9]+$', '请输入数字!'),  # 第一个参数为正则表达式, 第二个参数为校验不通过时的报错信息
            RegexValidator(r'^159[0-9]+$', '数字必须以159开头!'),
        ]
    )
'''

钩子函数

书写代码校验字段输入是否合法, 在其他校验合法之后再进行钩子函数代码校验

局部钩子: 校验单个字段

'''
class MyForm(forms.Form):
    ...

    # 校验用户名中不能含有666
    def clean_username(self):
        username = self.cleaned_data.get('username')
        if '666' in username:
            self.add_error('username', '光喊666是不行的')

        return username  
'''

全局钩子: 校验多个字段

'''
class MyForm(forms.Form):
    ...  

    # 校验两次输入密码是否一致
    def clean(self):
        password = self.cleaned_data.get('password')
        confirm_password = self.cleaned_data.get('confirm_password')
        if not confirm_password == password:
            self.add_error('confirm_password', '两次密码不一致!')

        return self.cleaned_data
'''

其他字段及参数

需要掌握

'''
class MyForm(forms.Form):
    username = forms.CharField(
        ...,
        label='用户名',  # input框对应的提示信息
        initial='jason',  # 初始值
        required=False,  # 允许字段值为空
        widget=forms.widgets.PasswordInput(attrs={'class': 'form-control c1', 'pwd': '123'}),  # 密文展示, 给input框设置样式及属性
        ...
    )

# 前端对应标签: <input type="password" ... class="form-control c1" pwd="123" ...>
'''

了解, 会copy即可

'''
radioSelect:
    gender = forms.fields.ChoiceField(
            choices=((1, "男"), (2, "女"), (3, "保密")),
            label="性别",
            initial=3,
            widget=forms.widgets.RadioSelect()
        )
 
单选Select下拉框
    hobby = forms.ChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
        label="爱好",
        initial=3,
        widget=forms.widgets.Select()

多选Select框, 无需下拉
    hobby = forms.MultipleChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
        label="爱好",
        initial=[1, 3],
        widget=forms.widgets.SelectMultiple()
    )
    
单选checkbox
    keep = forms.ChoiceField(
        label="是否记住密码",
        initial="checked",
        widget=forms.widgets.CheckboxInput()
    )

多选checkbox
    hobby = forms.MultipleChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
        label="爱好",
        initial=[1, 3],
        widget=forms.widgets.CheckboxSelectMultiple()
    )
'''

猜你喜欢

转载自www.cnblogs.com/-406454833/p/12011928.html
今日推荐