灵虚御风
醉饮千觞不知愁,忘川来生空余恨!

导航

 
今日内容:
    多对多创建方式

    forms组件

    cookie和session



     多对多三种创建方式
        1.全自动(推荐使用*)
            优势:不需要你手动创建第三张表
            不足:由于第三张表不是你手动创建的,也就意味着第三张表字段是固定的无法做扩展
            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.纯手动(了解即可)
            自己创建第三张表
            优势:第三张可以任意的扩展字段
            不足:orm查询不方便
            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)
                # 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)

    forms组件
        自己手动实现一个注册功能
        当用户的用户名包含金进瓶梅    提示不符合社会主义核心价值观
        当用户的密码短于3位         提示密码太短了 不符合要求


        1.前端页面搭建                     >>>        渲染页面
        2.将数据传输到后端做校验        >>>        校验数据
        3.展示错误信息                    >>>        展示信息

        forms组件能够直接帮你完成上面的三步操作
            1.渲染前端页面
            2.校验数据是否合法
            3.展示错误信息

        1.forms组件基本用法
            1.写一个基础了forms.Form的类
                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必须是邮箱格式

            2.基本使用
                from app01 import views
                1.将需要校验的数据 以字典的方式传递给自定义的类 实例化产生对象
                    form_obj = views.LoginForm({'username':'jason','password':'123','email':'123'})
                2.如何查看数据是否全部合法
                    form_obj.is_valid()  # 只有所有的数据都符合要求 才会是True
                    False
                3.如何查看错误原因
                    form_obj.errors
                    {
                    'password': ['Ensure this value has at least 5 characters (it has 3).'],
                    'email': ['Enter a valid email address.']
                    }
                4.如何查看通过校验的数据
                    form_obj.cleaned_data
                    {'username': 'jason'}


                注意事项:
                    1.自定义类中所有的字段默认都是必须要传值的
                    2.可以额外传入类中没有定义的字段名 forms组件不会去校验 也就意味着多传一点关系没有
                    form_obj = views.LoginForm({'username':'jason','password':'123456','email':'123@qq.com'})
                    form_obj.is_valid()
                    True

                    form_obj = views.LoginForm({'username':'jason','password':'123456'})
                    form_obj.is_valid()
                    False

                    form_obj = views.LoginForm({'username':'jason','password':'123456','email':'123@qq.com','hobby':'read'})
                    form_obj.is_valid()
                    True

        2.渲染页面
            三种方式
                <p>第一种渲染页面的方式(封装程度太高 一般只用于本地测试  通常不适用)</p>
                {{ form_obj.as_p }}
                {{ form_obj.as_ul }}
                {{ form_obj.as_table }}

                <p>第二种渲染页面的方式(可扩展性较高 书写麻烦)</p>
                <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>

                <p>第三种渲染页面的方式(推荐)</p>
                {% for foo in form_obj %}
                    <p>{{ foo.label }}{{ foo }}</p>
                {% endfor %}
            注意事项
                1.forms组件在帮你渲染页面的时候 只会渲染获取用户输入的标签  提交按钮需要你手动添加

                2.input框的label注释  不指定的情况下 默认用的类中字段的首字母大写

        校验数据的时候可以前后端都校验 做一个双重的校验
        但是前端的校验可有可无 而后端的校验则必须要有,因为前端的校验可以通过爬虫直接避开
            前端取消浏览器校验功能
                form标签指定novalidate属性即可
                    <form action="" method='post' novalidate></form>

        3.展示错误信息
            {% for foo in form_obj %}
                <p>{{ foo.label }}:{{ foo }}
                <span>{{ foo.errors.0 }}</span>
                </p>
            {% endfor %}

            后端代码
            password = forms.CharField(max_length=8,min_length=5,label='密码',error_messages={
                                   'max_length':'密码最大八位',
                                   'min_length':'密码最小五位',
                                   'required':'密码不能为空'
                               },required=False,validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')])  # 密码最长八位最短五位


        4.钩子函数(HOOK)
            forms组件暴露给用户 可以自定义的校验规则

            全局钩子


            局部钩子


            用法:在自定义的form类中书写方法即可
            # 局部钩子(针对某一个字段做额外的校验)   校验用户名中不能包含666 一旦包含 提示
            def clean_username(self):
                username = self.cleaned_data.get('username')
                if '666' in username:
                    self.add_error('username','光喊666是不行的 你得自己上')
                return username

            # 全局钩子(针对多个字段做额外的校验)    校验用户两次密码是否一致
            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



        5.forms组件其他字段及操作方式
            required  是否必填
            label         注释信息
            error_messages  报错信息

            initial        默认值

            widget        控制标签属性和样式
                widget=widgets.PasswordInput()
                控制标签属性
                     widget=widgets.PasswordInput(attrs={'class':'form-control c1 c2','username':'jason'})

            其他字段了解知识点(知道有这些对象 需要用到的时候 能够知道去哪找)
                # 单选的radio框
                gender = forms.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框
                hobby1 = 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
                hobby2 = forms.MultipleChoiceField(
                    choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
                    label="爱好",
                    initial=[1, 3],
                    widget=forms.widgets.CheckboxSelectMultiple()
                )



        forms组件源码分析
            form_obj.is_valid()


    cookie与session
        由于http协议是无状态的 无法记录用户状态

        cookie就是保存在客户端浏览器上的键值对
            工作原理:当你登陆成功之后 浏览器上会保存一些信息
            下次再访问的时候 就会带着这些信息去访问服务端  服务端通过这些信息来识别出你的身份

            cookie虽然是写在客户端浏览器上的  但是是服务端设置的
            浏览器可以选择不服从命令 禁止写cookie


        session就是保存在服务器上的键值对
            session虽然是保存在服务器上的键值对
            但是它是依赖于cookie工作的

            服务端返回给浏览器一个随机的字符串
            浏览器以键值对的形式保存
            sessionid:随机字符串

            浏览器在访问服务端的时候  就会将随机字符串携带上
            后端获取随机串与后端的记录的做比对
                随机字符串1:数据1
                随机字符串2:数据2

    如何操作Cookie
        django返回给客户端浏览器的都必须是HttpResponse对象
        return HttpResponse()
        return render()
        return redirect()



        obj1 = HttpResponse()
        return obj1
        obj2 = render()
        return obj2
        obj3 = redirect()
        return obj3



        设置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
        设置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表中,保存的数据 可以在后端任意位置获取到





    作业
        基于session完整登陆校验
总结
多对多三种创建方式
        1.全自动
            完全依赖于ManyToMany让django orm自动创建第三张表
            优势:不需要你创建第三张表  自动创建
            不足:第三张表扩展性
        2.纯手动
            不依赖于ManyToMany,自己创建第三张表,里面是有ForeignKey自己做两张表的关联
            优势:第三张可以新增任意字段 扩展性较高
            不足:orm查询时较为繁琐
        3.半自动(推荐使用 因为可以给你后续的项目迭代提供方便)
            依赖于ManyToMany,但是自己创建第三张表
            优势:可扩展性高
        不足:多对多字段方法不支持了(add,set,remove,clear)

    forms组件
        forms组件三大功能:
            1.渲染前端获取用户输入的标签
            2.校验数据
            3.展示错误信息
            注意:forms组件只能渲染获取用户输入的标签  提交按钮需要用户自己写

        1.基本使用
            forms组件中所有的字段默认都是必填的(默认就是required=True)
            from  django import forms

            class MyForm(forms.Form):
                username = forms.CharField(max_length=8)
                email = forms.EmailField()
        2.先生成一个对象
            form_obj = MyForm({'username':'jason','email':'123@qq.com'})
        3.判断数据是否合法
            form_obj.is_valid()
            # 只有数据全部满足条件才会返回True
        4.获取符合条件的数据
            form_obj.cleaned_data
        5.获取不符合条件的数据的报错原因
            form_obj.errors
        6.渲染前端页面  先生成一个空对象 并将对象传递给前端页面
            form_obj = MyForm()
        7.前端页面有三种渲染方式
            1.{{form_obj.as_p}}  # 封装程度太高 可扩展性差
            2.{{ form_obj.username.label }}{{form_obj.username}}  # 书写的内容太多了
            3.    {% for form in form_obj %}  # 使用频率较高
                    <p> {{form.label}}{{ form }}</p>
                {% endfor %}
        8.其他属性操作
            from  django.forms import widgets
            username = forms.CharField(max_length=8,label='用户名',required=False,
                                        error_message={
                                            'max_length':"用户名最大八位",
                                            'required':'用户名不能为空'
                                        },
                                        widget=widgets.TextInput(attrs={'class':'form-control'},
                                        validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')]
                                        )
                                    )
        9.钩子函数(Hook)
            局部钩子 (针对某一个字段做一些额外的校验)
            from app01 import models
            def clean_username(self):
                # 当前用户名是否已经被注册
                username = self.cleaned_data.get('username')
                is_user = models.User.objects.filter(username=username)
                if is_user:
                    self.add_error('username','用户名已经存在')
                if '金进瓶梅' in username:
                    self.add_error('username','不符合社会主义核心价值观')
                return username

            全局钩子(针对多个字段的校验)
            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

        10.其他字段及参数
            initial  默认值
            如果是单选的话  统一都是forms.ChocieField(
                    widget=widgets.Select(),
                    widget=widgets.RadioSelect(),
                    widget=widgets.CheckboxSelect(),
            )


    Cookie与Session
        由于http协议是无状态

        cookie是保存在客户端浏览器上的
        session是保存服务端上的
        session是依赖于cookie的,所有的保存用户登录状态或者各种校验基本都需要
        依赖于cookie

        django操作cookie与session
            操作的cookie要利用HttpResponse对象
            obj = HttpResponse()
            obj.set_cookie('k1','v1',max_age=100)
            return obj


            request.COOKIES.get('k1')


            request.session['name'] = 'jason'  # 三件事
            # 1.生成一个随机字符串
            # 2.将随机字符串和要保存的数据写入django_session表中(django默认session过期时间14天)
            # 3.将随机字符串返回给客户端浏览器
            """
            服务端保存用户信息 不一定非要在django_session表中保存
            可以利用其他数据库或者换成作为session的暂存地
            """


            request.session.get('name')  # 三件事


            # 删除当前会话的所有Session数据
            request.session.delete()
              
            # 删除当前的会话数据并删除会话的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失效策略。

        利用cookie写了装饰器

        作业用session
今日内容

 form 基本校验规则.png

cookies 在浏览器位置

 

 

from django.db import models

# Create your models here.

"""多对多创建第三张表"""
"""1.全自动推介使用
            优势:不需要你手动创建第三张表
            不足:由于第三张表不是你手动创建的,也就意味着第三张表字段是固定的无法做扩展
"""
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.纯手动 (了解即可)
自己创建第三张表
            优势:第三张可以任意的扩展字段
            不足:orm查询不方便
"""

# 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.半自动(推介使用)
优势:结合了全自动和纯手动的两个优点
    1. 可以orm跨表查询
    2.方便扩展

"""
"""
多对多字段的
add
set
remove
clear都不支持
"""
# 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 表中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)
models.py

python3 manage.py makemigrations|migrate

 

"""
Django settings for day58 project.

Generated by 'django-admin startproject' using Django 1.11.11.

For more information on this file, see
https://docs.djangoproject.com/en/1.11/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.11/ref/settings/
"""

import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '0_g4dlihb-sg65(=nygc6odm%s!ofh!f6a^qr%u)y^$kjwl34%'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01.apps.App01Config',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'day58.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')]
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'day58.wsgi.application'


# Database
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}


# Password validation
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/1.11/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.11/howto/static-files/

STATIC_URL = '/static/'
settings.py

 

templates
l

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>

</head>
<body>
<form action="" method="post">
    <p>username:
        <input type="text" name="username">
    </p>
    <p>password:
        <input type="password" name="password">
    </p>
    <input type="submit">
</form>
</body>
</html>
lg.html

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>

</head>
<body>
<form action="" method="post">
    <p>username:
        <input type="text" name="username">
        <span style="color:red">{{ errors.username }}</span>

    </p>
    <p>password:
        <input type="password" name="password">
        <span style="color: red">{{ errors.password }}</span>

    </p>
    <input type="submit">

</form>
</body>
</html>
login.html

 

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    
</head>
<body>
<form action="" method="post" novalidate>
<h1>novalidate 取消前端校验</h1>
    <p>第一种渲染页面方式(封装程度太高,一般只用于本地测试 通常不适用)</p>
{#    <p>被p标签包裹 as_p</p>#}
{#    {{ form_obj.as_p }}#}
{#    <p>被ul标签包裹 as_ul</p>#}
{#    {{ form_obj.as_ul }}#}
{#    <p>被table标签包裹 as_table</p>#}
{#    {{ form_obj.as_table }}#}
    <p>第二种渲染页面的方式(可扩展性较高 书写麻烦)</p>
{#    <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>#}
    <p>第三种渲染页面的方式(推荐)</p>
    {% for foo in form_obj %}
        <p>{{ foo.label }}:{{ foo }}
        <span>{{ foo.errors.0 }}</span>
        </p>
    {% endfor %}
    <input type="submit">
</form>
</body>
</html>
reg.html
from django.shortcuts import render,redirect,HttpResponse,reverse

# Create your views here.
"""form组件推导原理"""
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组件"""
from django import forms
from django.forms import widgets
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError
class LoginForm(forms.Form):
    # username = forms.CharField(max_length=8, min_length=3,label='用户')  # 用户名最长八位最短三位
    # password = forms.CharField(max_length=8, min_length=5)  # 密码最长八位最短五位
    # email = forms.EmailField()  # email必须是邮箱格式
    username = forms.CharField(
        max_length=8,
        min_length=3,
        label='用户名',
        initial='tankdsb',
        error_messages={
            'max_length':'用户名最大八位',
            'min_length':'用户名最小三位',
            'required':'用户名不能为空'
        },
        widget=widgets.TextInput()

    ) # 用户名最长八位最短三位

    password = forms.CharField(
        max_length=8,
        min_length=5,
        label='密码',
        error_messages={
            'max_length':'密码最大八位',
            'min_length':'密码最小五位',
            'required':'密码不能为空'
        },
        widget=widgets.PasswordInput(
            attrs={
                'class':'form-control c1 c2',
                'username':'jason'
            }) # 密码最长八位最短五位
    )
    confirm_password = forms.CharField(
        max_length=8,
        min_length=5,
        label='确认密码',
        error_messages={
            'max_length':'确认密码最大八位',
            'min_length': '确认密码最小五位',
            'required': '确认密码不能为空'
        },
        required=False,
        validators=[
            RegexValidator(r'^[0-9]+$','请输入数字'),
            RegexValidator(r'^159[0-9]+$','数字必须以159开头')
                    ]) # 密码最长八位最短五位

    email = forms.EmailField(
        label='邮箱',
        error_messages={
            'required':'邮箱不能为空',
            'invalid':'邮箱格式不正确'
        }) # email必须是邮箱格式

    # 单选 radio 框
    gender = forms.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框
    hobby1 = 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
    hobby2 = forms.MultipleChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
        label="爱好",
        initial=[1, 3],
        widget=forms.widgets.CheckboxSelectMultiple()
    )

    phone = forms.CharField(
        validators=[
            RegexValidator(r'^[0-9]+$','请输入数字'),
            RegexValidator(r'^159[0-9]+$','数字必须以159开头')
        ])

    # 局部钩子 (针对某一字段做额外的校验,校验用户名中不能包含666 一旦包含 提示)

    def clean_username(self):
        username = self.cleaned_data.get('username')
        if '666' in username:
            # raise ValidationError('奥术大师就卡的凯撒就肯定会')
            self.add_error('username','光喊666是不行的 你得自己上')
        return username

    # 全局钩子(针对多个字段做额外的校验)    校验用户两次密码是否一致

    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


def reg(request):
    # 1 现生成一个空的自定义类的对象
    form_obj = LoginForm()
    # 2 将对象传递给前端页面
    if request.method == 'POST':
        # 3 获取前端post请求提交过的数据
        # print(request.POST) # # 由于request.POST其实也是一个字典 所有可以直接传给LoginForm
        form_obj = LoginForm(request.POST)
        # 4.校验数据 让forms组件帮你去校验
        if form_obj.is_valid():
            # 5.如果数据全部通过, 应该写入数据库
            res = form_obj.cleaned_data
        # 6 如果不通过 一个像前端展示错误信息
        ret = form_obj.errors
    return render(request,'reg.html',locals())


def lg(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        if username == 'jason' and password == '123':
            # 先获取url中get请求携带的参数
            old_url = request.GET.get('next')
            # 判断用户是直接访问的登陆页面 还是从别的页面的调过来
            if old_url:
                obj = redirect(old_url)
            else:
                # 如果用户直接访问的登陆页面 那么登陆完成之后 直接跳到网站的首页
                obj = redirect('/home/')
            obj.set_cookie('name','jason',max_age=30) # 浏览器上就会保存键值对name:jason

            return obj
    return render(request,'lg.html')

# 装饰器
from functools import wraps
def login_auth(func):
    @wraps(func)
    def inner(request,*args,**kwargs):
        # request 中获取 cookie
        # print(request.path)
        # print(request.get_full_path())
        """
        request.get_full_path()返回的是【/200/?type=10】

     request.path --  获取当前url,(但不含参数)
        """
        target_url = request.get_full_path()
        if request.COOKIES.get('name'):
            res = func(request,*args,**kwargs)
            return res
        else:
            return redirect(f'/lg/?next={target_url}')
    return inner

@login_auth
def home(request):
    # 先校验客户端cookie中有没有你写入的键值对
    # if request.COOKIES.get('name'):
    #     return HttpResponse('home页面 只有登录了才能看')
    # return redirect('/lg/')
    return HttpResponse('home页面 只有登录了才能看')
@login_auth
def index(request):
    return HttpResponse("index页面 只有登录了才能访问")

@login_auth
def xxx(request):
    return HttpResponse('xxx页面 登陆之后才能看')

@login_auth
def logout(request):
    obj = redirect('/lg/')
    obj.delete_cookie('name')
    return obj



def set_session(request):
    # request.session['name'] = 'jason'
    # request.session['name1'] = 'jason1'
    # request.session['name2'] = 'jason2'
    # request.session['name3'] = 'jason3'
    request.session['xxx'] = 'xxx'
    request.session.set_expiry(30)
    return HttpResponse('set_session')


def get_session(request):
    # print(request.session.get('name'))
    # print(request.session.get('name1'))
    # print(request.session.get('name2'))
    # print(request.session.get('name3'))
    print(request.session.get('xxx'))
    return HttpResponse('get_session')



def delete_session(request):
    # request.session.delete('xxx')
    request.session.flush()
    return HttpResponse('delete_session')
views.py
"""day58 URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/1.11/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.conf.urls import url, include
    2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^login/',views.login),
    url(r'^reg/',views.reg),
    url(r'^lg/', views.lg),
    url(r'^home/', views.home),
    url(r'^index/', views.index),
    url(r'^xxx/', views.xxx),
    url(r'^logout/', views.logout),
    url(r'^set_session/',views.set_session),
    url(r'^get_session/',views.get_session),
    url(r'^delete_session/',views.delete_session),
]
urls.py

 

posted on 2022-04-13 14:20  没有如果,只看将来  阅读(15)  评论(0编辑  收藏  举报