不忘初心,
牢记使命。

Django基础---Form和modelform校验器、同源和跨域问题

2021-04-06 大聪明 0评论 179 0喜欢

Form和modelform

Form自动生成登录标签并校验

# views.py
class LoginForm(forms.Form):

    name = forms.CharField(
        label='用户名:',
        initial='小李',
        max_length=16,
        min_length=6,
        widget=forms.widgets.TextInput(attrs={'class':'form-control'}),  # 密码输入不可见,括号里边加样式
    )

    password = forms.CharField(
        label='密码:',
        widget=forms.widgets.PasswordInput(attrs={'class':'form-control'}),  # 密码输入不可见,括号里边加样式
    )

    sex = forms.ChoiceField(
        label='性别',
        choices=((1,"男"), (2, "女"), (3, "其他")),
        widget=forms.widgets.RadioSelect(),
        initial=3,
    )

    city = forms.ChoiceField(
        label='城市',
        choices=((1,"北京"), (2, "上海"), (3, "东莞")),
        widget=forms.widgets.Select(),  # 下拉框
        initial=3,
    )

    hobby = forms.ChoiceField(
        label='爱好',
        choices=((1,"抽烟"), (2, "喝酒"), (3, "烫头")),
        widget=forms.widgets.CheckboxSelectMultiple,  # 多选框, SelectMultiple多选下拉框
        initial=3,
    )

    birthday = forms.CharField(
        label='生日',
        widget=forms.widgets.TextInput(attrs={'type':'date'}),
    )

def register(request):
    form_obj = LoginForm()
    if request.method == 'GET':
        return render(request, 'register.html',{'form_obj':form_obj})
    else:
        username = request.POST.get('name')
        password = request.POST.get('password')
        print(username, password)
        return HttpResponse('登录成功')
# register.html
<form action="" method="post">
    {% csrf_token %}
{#    用户名:<input type="text" name="username">#}
{#    密码:<input type="password" name="password">#}
    <div>
        <label for="">{{ form_obj.name.label }}</label>
        {{ form_obj.name }}
    </div>
    <div>
        <label for="">{{ form_obj.password.label }}</label>
        {{ form_obj.password }}
    </div>
    <div>
        <label>{{ form_obj.sex.label }}</label>
        {{ form_obj.sex }}
    </div>
    <div>
        <label>{{ form_obj.city.label }}</label>
        {{ form_obj.city }}
    </div>
    <div>
        <label>{{ form_obj.hobby.label }}</label>
        {{ form_obj.hobby }}
    </div>
    <div>
        <label>{{ form_obj.birthday.label }}</label>
        {{ form_obj.birthday }}
    </div>
{#    {{ form_obj.as_p }}#}
    <input type="submit">
</form>

其他属性

class LoginForm(forms.Form):

    name = forms.CharField(
        required=False,
        label='用户名:',
        initial='小李',
        max_length=16,
        min_length=6,
        error_messages={'requried':'不能为空','min_length':'不能太短'},
        widget=forms.widgets.TextInput(attrs={'class':'form-control'}),  # 密码输入不可见,括号里边加样式
    )

def register(request):
    form_obj = LoginForm()
    if request.method == 'GET':
        return render(request, 'register.html',{'form_obj':form_obj})
    else:
        # username = request.POST.get('name')
        # password = request.POST.get('password')
        # print(username, password)
        # request.POST = name:"ssss"
        form_obj = LoginForm(request.POST)
        if form_obj.is_valid():  # 做校验
            print(form_obj.cleaned_data)  # 通过的校验数据
        else:
            print(form_obj.errors)
            return render(request, 'register.html', {'form_obj':form_obj})

        return HttpResponse('登录成功')

{##novalidate 关闭浏览器校验#}
<form action="" method="post" novalidate>
    {% csrf_token %}
{#    用户名:<input type="text" name="username">#}
{#    密码:<input type="password" name="password">#}
    <div>
        <label for="">{{ form_obj.name.label }}</label>
        {{ form_obj.name }}
{#        # 不取列表,只取一个#}
        {{ form_obj.name.errors.0 }}
    </div>
    <input type="submit">
</form>

校验器组件

import re
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 LoginForm(forms.Form):

    name = forms.CharField(
        required=False,
        label='用户名:',
        initial='小李',
        max_length=16,
        min_length=6,
        error_messages={'requried':'不能为空','min_length':'不能太短'},
        # validators=[RegexValidator(r'^金瓶梅','没看过金瓶梅不能通过'),],
        validators=[mobile_validate, ],
        widget=forms.widgets.TextInput(attrs={'class':'form-control'}),  # 密码输入不可见,括号里边加样式
    )

Hook钩子方法

在Form类中定义钩子函数,来实现自定义的验证功能。

源码分析:https://www.bilibili.com/video/BV1aJ411H7Ej?p=405

局部钩子和全局钩子

import re
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 LoginForm(forms.Form):

    name = forms.CharField(
        required=False,
        label='用户名:',
        initial='小李',
        max_length=16,
        min_length=6,
        error_messages={'requried':'不能为空','min_length':'不能太短'},
        validators=[RegexValidator(r'^金瓶梅','没看过金瓶梅不能通过'),],
        # validators=[mobile_validate, ],
        widget=forms.widgets.TextInput(attrs={'class':'form-control'}),  # 密码输入不可见,括号里边加样式
    )
    # 局部钩子
    def clean_name(self):
        value = self.cleaned_data['name']
        if '小李' in value:
            raise ValidationError('含有敏感词汇:小李')
        else:
            return value
    # 全局钩子
    def clean(self):
        value = self.cleaned_data

        p1 = value['password']
        p2 = value['r_password']
        if p1 == p2:
            return value
        else:
            # raise ValidationError('两次输入的密码不一致')
            self.add_error('r_password','两次输入的密码不一致')
            raise ValidationError('两次输入的密码不一致')


<form action="" method="post" novalidate>
    {% csrf_token %}
{#    用户名:<input type="text" name="username">#}
{#    密码:<input type="password" name="password">#}
    <div>
        <label for="">{{ form_obj.name.label }}</label>
        {{ form_obj.name }}
{#        # 不取列表,只取一个#}
        {{ form_obj.name.errors.0 }}
    </div>
    <div>
        <label for="">{{ form_obj.password.label }}</label>
        {{ form_obj.password }}
    </div>
    <div>
        <label for="">{{ form_obj.r_password.label }}</label>
        {{ form_obj.r_password }}
    </div>

# html
<body>
<div class="container">
    <h1>student</h1>
    <form method="POST" novalidate>
        {% csrf_token %}
        {# {{ student_list.as_p }}#}
        {% for student in student_list %}
            <div class="form-group col-md-6">
                {# 拿到数据字段的verbose_name,没有就默认显示字段名 #}
                <label class="col-md-3 control-label">{{ student.label }}</label>
                <div class="col-md-9" style="position: relative;">{{ student }}</div>
            </div>
        {% endfor %}
        <div class="col-md-2 col-md-offset-10">
            <input type="submit" value="提交" class="btn-primary">
        </div>
    </form>
</div>
</body>

获取数据库中数据并展示

publishs = forms.ModelChoiceField(
    label='出版社',
    queryset=models.Publish.objects.all(),
)

modelform

modelform会自动生成你的model类(表)对应的字段的Form类

# models.py
class Book(models.Model):

    nid = models.AutoField(primary_key=True)
    title = models.CharField( max_length=32)
    publishDate=models.DateField()
    price=models.DecimalField(max_digits=5,decimal_places=2)
    publish=models.ForeignKey(to="Publish",to_field="nid")
    authors=models.ManyToManyField(to='Author',)
    def __str__(self):
       return self.title

# views.py
class BookForm(forms.ModelForm):

    class Meta:
        model = models.Book
        fields = "__all__"
        labels = {
            "title": "书名",
            "price": "价格"
        }
        widgets = {
            "password": forms.widgets.PasswordInput(attrs={"class": "c1"}),
            "publishDate": forms.widgets.DateInput(attrs={"type": "date"}),
        }
    #局部钩子:
    def clean_title(self):
        pass
  #全局钩子
    def clean(self):
        pass
    def __init__(self,*args,**kwargs): #批量操作
        super().__init__(*args,**kwargs)
        for field in self.fields:
            #field.error_messages = {'required':'不能为空'} #批量添加错误信息,这是都一样的错误,不一样的还是要单独写。
            self.fields[field].widget.attrs.update({'class':'form-control'})

class meta常用参数

model = models.Book  # 对应的Model中的类
fields = "__all__"  # 字段,如果是__all__,就是表示列出所有的字段
exclude = None  # 排除的字段
labels = None  # 提示信息
help_texts = None  # 帮助提示信息
widgets = None  # 自定义插件
error_messages = None  # 自定义错误信息
error_messages = {
    'title':{'required':'不能为空',...} #每个字段的所有的错误都可以写,...是省略的意思,复制黏贴我代码的时候别忘了删了...
}

任务

CRM 客户关系管理系统

(jq22.com 登录注册模板 扒页面模板)

同源和跨域

深入理解python异步编程

同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。 

简单请求跨域

创建两个django项目,第一个叫做s1,一个叫做s2,s1用8000端口启动,s2用8001端口启动

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h2>s1的首页</h2>
<button id="btn">Ajax请求</button>


<script src="https://cdn.bootcss.com/jquery/3.4.0/jquery.js"></script>
<script>
    $('#btn').click(function () {
        $.ajax({
            //url:'/books/', 访问自己服务器的路由,同源(ip地址、协议、端口都相同才是同源)
            url:'http://127.0.0.1:8001/books/', //访问其他服务器的路由,不同源,那么你可以访问到另外一个服务器,但是浏览器将响应内容给拦截了,并给你不同源的错误:Access to XMLHttpRequest at 'http://127.0.0.1:8001/books/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'http://127.0.0.1:8002' that is not equal to the supplied origin.
            #并且注意ip地址和端口后面是一个斜杠,如果s2的这个url没有^books的^符号,那么可以写两个//。        type:'get',
            success:function (response) {
                console.log(response);
            }

        })
    })


</script>
</body>
</html>


from django.shortcuts import render,HttpResponse
from django.http import JsonResponse
# Create your views here.

def index(request):
    return render(request,'index.html')

def books(request):

    # return JsonResponse(['西游记','三国演义','水浒传'],safe=False)
    obj = JsonResponse(['西游记','三国演义','水浒传'],safe=False)
    return obj


# s2
from django.shortcuts import render
from django.http import JsonResponse
# Create your views here.
def books(request):

    # return JsonResponse(['西游记2','三国演义2','水浒传2'],safe=False)

    obj = JsonResponse(['西游记2','三国演义2','水浒传2'],safe=False)
    #下面这个响应头信息是告诉浏览器,不要拦着,我就给它,"*"的意思是谁来请求我,我都给
    # obj["Access-Control-Allow-Origin"] = "*"
    obj["Access-Control-Allow-Origin"] = "http://127.0.0.1:8000" #只有这个ip和端口来的请求,我才给他数据,其他你浏览器帮我拦着
    return obj

发表评论 取消回复

电子邮件地址不会被公开。

请输入正确格式的qq邮箱
请输入以http或https开头的URL,格式如:https://libo_sober.top