• Day25


    一、
    1. 信号
    需求: 数据库新增数据时,写一条日志,信号。

    Model signals
    pre_init # django的modal执行其构造方法前,自动触发
    post_init # django的modal执行其构造方法后,自动触发
    pre_save # django的modal对象保存前,自动触发
    post_save # django的modal对象保存后,自动触发
    pre_delete # django的modal对象删除前,自动触发
    post_delete # django的modal对象删除后,自动触发
    m2m_changed # django的modal中使用m2m字段操作第三张表(add,remove,clear)前后,自动触发
    class_prepared # 程序启动时,检测已注册的app中modal类,对于每一个类,自动触发
    Management signals
    pre_migrate # 执行migrate命令前,自动触发
    post_migrate # 执行migrate命令后,自动触发
    Request/response signals
    request_started # 请求到来前,自动触发
    request_finished # 请求结束后,自动触发
    got_request_exception # 请求异常后,自动触发
    Test signals
    setting_changed # 使用test测试修改配置文件时,自动触发
    template_rendered # 使用test测试渲染模板时,自动触发
    Database Wrappers
    connection_created # 创建数据库连接时,自动触发


    实现:
    from django.core.signals import request_finished
    from django.core.signals import request_started
    from django.core.signals import got_request_exception

    from django.db.models.signals import class_prepared
    from django.db.models.signals import pre_init, post_init
    from django.db.models.signals import pre_save, post_save
    from django.db.models.signals import pre_delete, post_delete
    from django.db.models.signals import m2m_changed
    from django.db.models.signals import pre_migrate, post_migrate

    from django.test.signals import setting_changed
    from django.test.signals import template_rendered

    from django.db.backends.signals import connection_created


    def callback1(sender, **kwargs):
    print(sender,kwargs)

    pre_save.connect(callback1)


    2. 缓存
    配置:
    开发调试
    内存
    文件
    数据库
    Memcache缓存(python-memcached模块)

    应用:
    a. 全站缓存(基于中间件实现)
    b. 视图函数做缓存(基于装饰器)
    c. 模板局部做缓存

    使用:
    a. 写中间件
    MIDDLEWARE = [
    # 'django.middleware.cache.UpdateCacheMiddleware',
    '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',
    # 'django.middleware.cache.FetchFromCacheMiddleware',
    ]
    b. 装饰器
    from django.shortcuts import render,HttpResponse
    from app01 import models
    from django.views.decorators.cache import cache_page


    import time

    @cache_page(60 * 15)
    def users(request):
    ctime = str(time.time())
    return HttpResponse(ctime)

    c. 模板
    {% load cache %}
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Title</title>
    </head>
    <body>
    <h1>{{ ctime }}</h1>
    {% cache 5000 xxxxx %}
    {{ ctime }}
    {% endcache %}
    </body>
    </html>



    二、
    Model - 数据库操作 - 验证 class A(MOdel): user = email = pwd = Form - class LoginForm(Form): email = fields.EmailField() user = pwd = - is_valid -> 每一个字段进行正则(字段内置正则)+clean_字段 -> clean(__all__) -> _post_clean - cleand_data - error


    Model + Form ==> ModelForm。model和form的结合体,所以有以下功能:
    • 验证
    • 数据库操作

    model有操作数据库的字段,form验证也有那几个字段,虽然耦合度降低,但是代码是有重复的。如果利用model里的字段,那是不是form里的字段就不用写了。

    models.py

    class UserType(models.Model):
        caption = models.CharField(max_length=32)
    
    class UserInfo(models.Model):
        username = models.CharField(max_length=32)
        email = models.EmailField()
        user_type = models.ForeignKey(to='UserType',to_field='id')

    forms.py

    from django import forms
    from django.forms import fields
    
    class UserInfoForm(forms.Form):
        # username = models.CharField(max_length=32)    <-- models
        username = fields.CharField(max_length=32)
        # email = models.EmailField()    <-- models
        email = fields.EmailField()
        # user_type = models.ForeignKey(to='UserType',to_field='id')    <-- models
        user_type = fields.ChoiceField(
            choices=models.UserType.objects.values_list('id','caption')
        )
    
        # 下面的操作是让数据在网页上实时更新。
        def __init__(self, *args, **kwargs):
            super(UserInfoForm,self).__init__(*args, **kwargs)
            self.fields['user_type'].choices = models.UserType.objects.values_list('id','caption')

    index.html

    <body>
        <form action="/index/" method="POST" novalidate="novalidate">
            {% csrf_token %}
            {{ obj.as_p }}
            <input type="submit" value="提交">
        </form>
    </body>

    novalidate 注: HTML5输入类型和浏览器验证

    如果表单中包含URLField、EmailField和其他整数字段类似,Django将使用url、email和number这样的HTML5输入类型。默认情况下,浏览器可能会对这些字段进行他们自身的验证,这些验证可能比Django的验证更严格。如果你想禁用这个行为,请设置form标签的novalidate属性,或者制定一个不同的字段,如TextInput。

    ModelForm 基本操作

    下面通过modelform实现

    forms.py

    class UserInfoModelForm(forms.ModelForm):
    
        class Meta:
            model = models.UserInfo    # 与models建立了依赖关系
            fields = "__all__"

    views.py

    def index(request):
        if request.method == "GET":
            obj = UserInfoModelForm()
            return render(request,"index.html",{'obj':obj})
        elif request.method == "POST":
            obj = UserInfoModelForm(request.POST)
            print(obj.is_valid())  # 这是方法,别忘记了加括号
            print(obj.cleaned_data)
            print(obj.errors)
            return render(request,"index.html",{'obj':obj})

    自定制字段名

    如何定义http上定义的字段呢,自定义写成中文的?之前的用法是在Form里写上label。Model Form定义要用verbose_name

    models.py

    class UserInfo(models.Model):
        username = models.CharField(max_length=32, verbose_name='用户')
        email = models.EmailField(verbose_name='邮箱')
        user_type = models.ForeignKey(to='UserType',to_field='id', verbose_name='类型')

    如果不在model里定义,在modelForm里实现,利用labels

    class UserInfoModelForm(forms.ModelForm):
    
        class Meta:
            model = models.UserInfo
            fields = "__all__"
            labels = {
                'username':'用户名',
                'email':'邮箱',
            }

     

    展示指定的列

    fields = "__all__"上面展示所有的,可不可以展示指定的列

            fields = ['username','email']   # 显示指定列
            exclude = ['username']          # 排除指定列

    modelForm里也能做验证?

    form里面有is_validcleaned_dataerrors

    # Form验证:
        UserInfoForm -> Form -> BaseForm( 包含is_valid等方法)
    
    # ModelForm验证:
        UserInfoModelForm -> ModelForm -> BaseModelForm -> BaseForm

    ModelForm组件

    ModelForm
        a.  class Meta:
                model,                           # 对应Model的
                fields=None,                     # 字段
                exclude=None,                    # 排除字段
                labels=None,                     # 提示信息
                help_texts=None,                 # 帮助提示信息
                widgets=None,                    # 自定义插件
                error_messages=None,             # 自定义错误信息(整体错误信息from django.core.exceptions import NON_FIELD_ERRORS)
                field_classes=None               # 自定义字段类 (也可以自定义字段)
                localized_fields=('birth_date',) # 本地化,如:根据不同时区显示数据
                如:
                    数据库中
                        2016-12-27 04:10:57
                    setting中的配置
                        TIME_ZONE = 'Asia/Shanghai'
                        USE_TZ = True
                    则显示:
                        2016-12-27 12:10:57
        b. 验证执行过程
            is_valid -> full_clean -> 钩子 -> 整体错误
    
        c. 字典字段验证
            def clean_字段名(self):
                # 可以抛出异常
                # from django.core.exceptions import ValidationError
                return "新值"
        d. 用于验证
            model_form_obj = XXOOModelForm()
            model_form_obj.is_valid()
            model_form_obj.errors.as_json()
            model_form_obj.clean()
            model_form_obj.cleaned_data
        e. 用于创建
            model_form_obj = XXOOModelForm(request.POST)
            #### 页面显示,并提交 #####
            # 默认保存多对多
                obj = form.save(commit=True)
            # 不做任何操作,内部定义 save_m2m(用于保存多对多)
                obj = form.save(commit=False)
                obj.save()      # 保存单表信息
                obj.save_m2m()  # 保存关联多对多信息
    
        f. 用于更新和初始化
            obj = model.tb.objects.get(id=1)
            model_form_obj = XXOOModelForm(request.POST,instance=obj)
            ...
    
            PS: 单纯初始化
                model_form_obj = XXOOModelForm(initial={...})

    注意:导入模块名(fields、widgets)和字段名重复,所以导入时要起个别名。

    from django import forms
    from django.forms import fields as Ffields
    from django.forms import widgets as Fwidgets
    class UserInfoModelForm(forms.ModelForm):
    
        is_rmb = Ffields.CharField(widget=Fwidgets.CheckboxInput())
    
        class Meta:
            model = models.UserInfo
            fields = '__all__'
            # fields =  ['username','email']
            # exclude = ['username']
            labels = {
                'username': '用户名',
                'email': '邮箱',
            }
            help_texts = {
                'username': '...'
            }
            widgets = {
                'username': Fwidgets.Textarea(attrs={'class': 'c1'})
            }
            error_messages = {
                '__all__':{    # 整体错误信息
    
                },
                'email': {
                    'required': '邮箱不能为空',
                    'invalid': '邮箱格式错误..',
                }
            }
            field_classes = {  # 定义字段的类是什么
                # 'email': Ffields.URLField  # 这里只能填类,加上括号就是对象了。
            }
    
            # localized_fields=('ctime',)  # 哪些字段做本地化

    ModelForm 数据库操作

    创建数据save

    如果数据验证是ok的,那么save,就直接在数据库中创建完数据了

            if obj.is_valid():
                obj.save()      # 创建数据

    在如下一对多、多对多关系中:

    class UserType(models.Model):
        caption = models.CharField(max_length=32)
    
    class UserGroup(models.Model):
        name = models.CharField(max_length=32)
    
    class UserInfo(models.Model):
        username = models.CharField(max_length=32)
        email = models.EmailField()
        user_type = models.ForeignKey(to='UserType',to_field='id')
        u2g = models.ManyToManyField(UserGroup)

    这样的话,执行上面的obj.save()会在UserInfo表和多对多关系表里都增加数据。

    views.py

    def index(request):
        if request.method == "GET":
            obj = UserInfoModelForm()
            return render(request,'index.html',{'obj': obj})
        elif request.method == "POST":
            obj = UserInfoModelForm(request.POST)
            if obj.is_valid():
                obj.save()  # 等价以下三句
                # instance = obj.save(False)
                # instance.save()
                # obj.save_m2m()
            return render(request,'index.html',{'obj': obj})

    save 做了哪些操作?

    save源码里:

    def save(self, commit=True):
        """"""
        if commit:
            self.instance.save()    # 指的当前model对象
            self._save_m2m()        # 指:保存m2m对象
        else:
            self.save_m2m = self._save_m2m
        return self.instance    # model 类的对象
        """"""

    所以instance = obj.save(False)时,什么都不会操作。

    if obj.is_valid():
        instance = obj.save(False)
        instance.save()     # 当前对象表数据创建
        obj.save_m2m()      # 多对多表数据创建
        # 上面这三句完成的是和上面 obj.save 一样的操作。拆开就可以自定制操作了

    修改数据

    修改表数据是,记得把instance信息也传进去,不然是新建数据,而不是对某行数据进行修改。

    编辑用户信息,新url方式保留默认数据

    urls.py

        url(r'^user_list/', views.user_list),
        url(r'^edit-(d+)/', views.user_edit),

    views.py

    def user_list(request):
        li = models.UserInfo.objects.all().select_related('user_type')  # 这里只能是外键,多对多字段也不可以
        return render(request,'user_list.html',{'li': li})
    
    def user_edit(request, nid):
        # 获取当前id对象的用户信息
        # 显示用户已经存在数据
        if request.method == "GET":
            user_obj = models.UserInfo.objects.filter(id=nid).first()
            mf = UserInfoModelForm(instance=user_obj)   # 把默认数据传递进去
            return render(request,'user_edit.html',{'mf': mf, 'nid': nid})
        elif request.method == 'POST':
            # 数据修改的信息,给数据库的哪一行做修改?
            user_obj = models.UserInfo.objects.filter(id=nid).first()
            mf = UserInfoModelForm(request.POST,instance=user_obj)  # 指定给谁做修改
            if mf.is_valid():
                mf.save()
            else:
                print(mf.errors.as_json())
            return render(request,'user_edit.html',{'mf': mf, 'nid': nid})

    user_list.html

    <body>
        <ul>
            {% for row in li %}
                <li>{{ row.username }} - {{ row.user_type.caption }} - <a href="/edit-{{ row.id }}/">编辑</a></li>
            {% endfor %}
        </ul>
    </body>

    user_edit.html

    <body>
        <form method="POST" action="/edit-{{ nid }}/">
            {% csrf_token %}
        {{ mf.as_p }}
            <input type="submit" value="提交" />
        </form>
    </body>

     

    ModelForm钩子、额外字段

    数据验证钩子

    从上面的Form和ModelForm中,他们都是继承了BaseForm,而is_valid是在BaseForm中定义的,所以ModelForm也能和Form一样使用各种钩子

    额外字段

    像网页上的checkbox,一个月内免登陆,用提交到数据库么?这个只需要设置session和cookie就可以了。

    views.py

    class UserInfoModelForm(forms.ModelForm):
    
        is_rmb = fields.CharField(widget=widgets.CheckboxInput())  # 额外字段
    
        class Meta:
            model = models.UserInfo
            fields = '__all__'

    总结

        1. 生成HTML标签:class Meta: ...
        2. mf = xxxModelForm(instance=ModelObj) 生成默认值
        3. 额外的标签, is_rmb = Ffields.CharField(widget=Fwidgets.CheckboxInput())
        4. 各种验证 is_valid() -> 各种钩子...
        5.  mf.save()
            # 或
            instance = mf.save(False)
            instance.save()
            mf.save_m2m()
  • 相关阅读:
    基于Spring+SpringMVC实现AOP日志记录功能service注入异常为null的解决办法
    关于SpringBoot项目打包没有把依赖的jar包一起打包的解决办法
    JavaFx项目打包成exe,并集成Jre,使Java项目在任意机器运行
    常用正则表达式
    SqlServer 2005及其以上版本能用的查询数据的行号
    js 中的倒计时功能
    数据库删除重复列
    【转】svn文件清除批处理工具
    JS获取当前页面名称
    sql 去除重复记录
  • 原文地址:https://www.cnblogs.com/jnbb/p/8277293.html
Copyright © 2020-2023  润新知