码农行者 码农行者
首页
  • Python

    • 语言特性
    • Django相关
    • Tornado
    • Celery
  • Golang

    • golang学习笔记
    • 对比python学习go
    • 模块学习
  • JavaScript

    • Javascript
  • 数据结构预算法笔记
  • ATS
  • Mongodb
  • Git
云原生
运维
垃圾佬的快乐
  • 数据库
  • 机器学习
  • 杂谈
  • 面试
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

DeanWu

软件工程师
首页
  • Python

    • 语言特性
    • Django相关
    • Tornado
    • Celery
  • Golang

    • golang学习笔记
    • 对比python学习go
    • 模块学习
  • JavaScript

    • Javascript
  • 数据结构预算法笔记
  • ATS
  • Mongodb
  • Git
云原生
运维
垃圾佬的快乐
  • 数据库
  • 机器学习
  • 杂谈
  • 面试
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Django 最佳实践-读书笔记 - 第十一章、第十二章 Form

    • 所有录入的数据使用form 来进行校验
      • 在 html 的form 中使用 post方法,除了查询。
        • 在使用http的form形式来修改数据时,记得使用 csrf来保护数据。
          • 理解怎么给 form 实例添加属性
            • 知道 form 校验是怎么工作的
              • 一些有用的 form 方法
                • 简单的 ModelForm 使用默认的校验即可。
                  • 自定义字段验证,进行特定的校验
                    • Overriding the Clean Stage of Validation
                      • 扩展 Django Form Field (2 CBVs, 2 Forms, 1 Model)
                        • 在views中,重复使用搜索 mixin
                        • 开发语言
                        • Python
                        • Best.Practices.for.Django
                        DeanWu
                        2016-06-26
                        目录

                        Django 最佳实践-读书笔记 - 第十一章、第十二章 Form

                        其他章节索引页

                        # 第十一章 Form

                        # 所有录入的数据使用form 来进行校验

                        面对复杂多变的需求,我们自行校验是比较困难的。将校验集中在form层,利用这久经考验的校验机制。

                        # 在 html 的form 中使用 post方法,除了查询。

                        # 在使用http的form形式来修改数据时,记得使用 csrf来保护数据。

                        除了 http 的形式外,ajax 提交的也要使用csrf 来保护数据。

                        # 理解怎么给 form 实例添加属性

                        # forms
                        from django import forms
                        from .models import Taster
                        
                        
                        class TasterForm(forms.ModelForm):
                            class Meta:
                                model = Taster
                                
                            def __init__(self, *args, **kwargs):
                                # set the user as an attribute of the form
                                self.user = kwargs.pop('user')
                                super(TasterForm, self).__init__(*args, **kwargs)
                        
                        1
                        2
                        3
                        4
                        5
                        6
                        7
                        8
                        9
                        10
                        11
                        12
                        13
                        # views
                        from django.views.generic import UpdateView
                        from braces.views import LoginRequiredMixin
                        from .forms import TasterForm
                        from .models import Taster
                        
                        class TasterUpdateView(LoginRequiredMixin, UpdateView):
                            model = Taster
                            form_class = TasterForm
                            success_url = "/someplace/"
                            
                            def get_form_kwargs(self):
                                """This method is what injects forms with their keyword arguments."""
                                # grab the current set of form #kwargs
                                kwargs = super(TasterUpdateView, self).get_form_kwargs()
                                # Update the kwargs with the user_id
                                kwargs['user'] = self.request.user
                                return kwargs
                        .
                        
                        
                        1
                        2
                        3
                        4
                        5
                        6
                        7
                        8
                        9
                        10
                        11
                        12
                        13
                        14
                        15
                        16
                        17
                        18
                        19
                        20

                        # 知道 form 校验是怎么工作的

                        当你调用 form.is valid()时,很多事情发生:

                        • 如果这个form已经绑定了数据,``form.is_valid()会调用form.full_clean()` 方法。
                        • form.full_clean() 方法会遍历form 的字段,挨个字段的校验他们。
                          • 进入字段的数据会通过 to_python()方法被强制转为python格式,否则会抛出ValidationError异常。
                          • 数据针对每个字段特有的规则或自定义的规则,进行校验。失败后,抛出ValidationError异常。
                          • 如果有自定的clean <field>()方法,此时会调用他们
                        • form.full_clean() 会执行 form.clean()方法。
                        • 如果是一个ModelForm实例,form.post_clean()会如下处理:
                          • 将 ModelForm 数据转成 Model 实例,而不管 form.is_valid() 是否严重通过。
                          • Calls the model’s clean() method. For reference, saving a model instance through the ORM does not call the model’s clean() method.

                        # 一些有用的 form 方法

                        • Add Errors to Forms with Form.add error()
                        • http://www.2scoops.co/1.8-form.errors.as_data/
                        • http://www.2scoops.co/1.8-form.errors.as_json/
                        • http://www.2scoops.co/1.8-form.has_error/
                        • http://www.2scoops.co/1.8-form.non_field_errors/

                        # 第 十二 章 Form 通用的技巧

                        # 简单的 ModelForm 使用默认的校验即可。

                        # flavors/views.py
                        from django.views.generic import CreateView, UpdateView
                        from braces.views import LoginRequiredMixin
                        from .models import Flavor
                        
                        
                        class FlavorCreateView(LoginRequiredMixin, CreateView):
                            model = Flavor
                            fields = ('title', 'slug', 'scoops_remaining')
                            
                            
                        class FlavorUpdateView(LoginRequiredMixin, UpdateView):
                            model = Flavor
                            fields = ('title', 'slug', 'scoops_remaining')
                        
                        1
                        2
                        3
                        4
                        5
                        6
                        7
                        8
                        9
                        10
                        11
                        12
                        13
                        14

                        # 自定义字段验证,进行特定的校验

                        # core/validators.py
                        from django.core.exceptions import ValidationError
                        
                        def validate_tasty(value):
                            """Raise a ValidationError if the value doesn't start with the
                            word 'Tasty'.
                            """
                            if not value.startswith(u"Tasty"):
                                msg = u"Must start with Tasty"
                                raise ValidationError(msg)
                                
                        # 直接将校验添加到 model中
                        # core/models.py
                        from django.db import models
                        from .validators import validate_tasty
                        
                        class TastyTitleAbstractModel(models.Model):
                            title = models.CharField(max_length=255, validators=[validate_tasty])
                            class Meta:
                                abstract = True
                                
                        # flavors/models.py
                        from django.core.urlresolvers import reverse
                        from django.db import models
                        from core.models import TastyTitleAbstractModel
                        
                        class Flavor(TastyTitleAbstractModel):
                            slug = models.SlugField()
                            scoops_remaining = models.IntegerField(default=0)
                            def get_absolute_url(self):
                                return reverse("flavors:detail", kwargs={"slug": self.slug})
                                
                        # 仅将校验添加到form 中    
                        # flavors/forms.py
                        from django import forms
                        from core.validators import validate_tasty
                        from .models import Flavor
                        
                        class FlavorForm(forms.ModelForm):
                            def __init__(self, *args, **kwargs):
                            super(FlavorForm, self).__init__(*args, **kwargs)
                            self.fields["title"].validators.append(validate_tasty)
                            self.fields["slug"].validators.append(validate_tasty)
                            class Meta:
                                model = Flavor
                        
                        1
                        2
                        3
                        4
                        5
                        6
                        7
                        8
                        9
                        10
                        11
                        12
                        13
                        14
                        15
                        16
                        17
                        18
                        19
                        20
                        21
                        22
                        23
                        24
                        25
                        26
                        27
                        28
                        29
                        30
                        31
                        32
                        33
                        34
                        35
                        36
                        37
                        38
                        39
                        40
                        41
                        42
                        43
                        44
                        45

                        # Overriding the Clean Stage of Validation

                        原因:

                        • 对多Multi-field 的校验
                        • 避免重复验证(Validation involving existing data from the database that has already been validated)
                        # flavors/forms.py
                        from django import forms
                        from flavors.models import Flavor
                        
                        class IceCreamOrderForm(forms.Form):
                            """Normally done with forms.ModelForm. But we use forms.Form here
                            to demonstrate that these sorts of techniques work on every
                            type of form.
                            """
                            slug = forms.ChoiceField("Flavor")
                            toppings = forms.CharField()
                            
                            def __init__(self, *args, **kwargs):
                                super(IceCreamOrderForm, self).__init__(*args,
                                **kwargs)
                                # We dynamically set the choices here rather than
                                # in the flavor field definition. Setting them in
                                # the field definition means status updates won't
                                # be reflected in the form without server restarts.
                                self.fields["slug"].choices = [
                                (x.slug, x.title) for x in Flavor.objects.all()
                                ]
                                # NOTE: We could filter by whether or not a flavor
                                # has any scoops, but this is an example of
                                # how to use clean_slug, not filter().
                                
                            def clean_slug(self):
                                slug = self.cleaned_data["slug"]
                                if Flavor.objects.get(slug=slug).scoops_remaining <= 0:
                                    msg = u"Sorry, we are out of that flavor."
                                    raise forms.ValidationError(msg)
                                return slug
                        
                            def clean(self):
                                cleaned_data = super(IceCreamOrderForm, self).clean()
                                slug = cleaned_data.get("slug", "")
                                toppings = cleaned_data.get("toppings", "")
                                
                                # Silly "too much chocolate" validation example
                                if u"chocolate" in slug.lower() and \
                                    u"chocolate" in toppings.lower():
                                    msg = u"Your order has too much chocolate."
                                    raise forms.ValidationError(msg)
                                return cleaned_data
                        
                        1
                        2
                        3
                        4
                        5
                        6
                        7
                        8
                        9
                        10
                        11
                        12
                        13
                        14
                        15
                        16
                        17
                        18
                        19
                        20
                        21
                        22
                        23
                        24
                        25
                        26
                        27
                        28
                        29
                        30
                        31
                        32
                        33
                        34
                        35
                        36
                        37
                        38
                        39
                        40
                        41
                        42
                        43
                        44

                        # 扩展 Django Form Field (2 CBVs, 2 Forms, 1 Model)

                        2个 view,2个form 对应一个model

                        # stores/models.py
                        from django.core.urlresolvers import reverse
                        from django.db import models
                        
                        class IceCreamStore(models.Model):
                            title = models.CharField(max_length=100)
                            block_address = models.TextField()
                            phone = models.CharField(max_length=20, blank=True)
                            description = models.TextField(blank=True)
                            
                            def get_absolute_url(self):
                                return reverse("store_detail", kwargs={"pk": self.pk})
                                
                        # stores/forms.py
                        # Call phone and description from the self.fields dict-like object
                        from django import forms
                        from .models import IceCreamStore
                        class IceCreamStoreUpdateForm(forms.ModelForm):
                        
                            class Meta:
                                model = IceCreamStore
                            
                            def __init__(self, *args, **kwargs):
                                # Call the original __init__ method before assigning
                                # field overloads
                                super(IceCreamStoreUpdateForm, self).__init__(*args,
                                **kwargs)
                                self.fields["phone"].required = True
                                self.fields["description"].required = True
                        
                        
                        # stores/forms.py
                        from django import forms
                        from .models import IceCreamStore
                        class IceCreamStoreCreateForm(forms.ModelForm):
                            class Meta:
                                model = IceCreamStore
                                fields = ("title", "block_address", )
                                
                        class IceCreamStoreUpdateForm(IceCreamStoreCreateForm):
                            def __init__(self, *args, **kwargs):
                                super(IceCreamStoreUpdateForm,
                                self).__init__(*args, **kwargs)
                                self.fields["phone"].required = True
                                self.fields["description"].required = True
                            class Meta(IceCreamStoreCreateForm.Meta):
                                # show all the fields!
                                fields = ("title", "block_address", "phone",
                                "description", )
                                
                        # stores/views
                        from django.views.generic import CreateView, UpdateView
                        from .forms import IceCreamStoreCreateForm
                        from .forms import IceCreamStoreUpdateForm
                        from .models import IceCreamStore
                        class IceCreamCreateView(CreateView):
                            model = IceCreamStore
                            form_class = IceCreamStoreCreateForm
                        class IceCreamUpdateView(UpdateView):
                            model = IceCreamStore
                            form_class = IceCreamStoreUpdateForm
                        
                        1
                        2
                        3
                        4
                        5
                        6
                        7
                        8
                        9
                        10
                        11
                        12
                        13
                        14
                        15
                        16
                        17
                        18
                        19
                        20
                        21
                        22
                        23
                        24
                        25
                        26
                        27
                        28
                        29
                        30
                        31
                        32
                        33
                        34
                        35
                        36
                        37
                        38
                        39
                        40
                        41
                        42
                        43
                        44
                        45
                        46
                        47
                        48
                        49
                        50
                        51
                        52
                        53
                        54
                        55
                        56
                        57
                        58
                        59
                        60
                        61

                        # 在views中,重复使用搜索 mixin

                        一个搜索 from 在2个view 中使用。

                        # core/views.py
                        class TitleSearchMixin(object):
                            def get_queryset(self):
                                # Fetch the queryset from the parent's get_queryset
                                queryset = super(TitleSearchMixin, self).get_queryset()
                                # Get the q GET parameter
                                q = self.request.GET.get("q")
                                if q:
                                    # return a filtered queryset
                                    return queryset.filter(title__icontains=q)
                                # No q is specified so we return queryset
                                return queryset
                                
                        # add to flavors/views.py
                        from django.views.generic import ListView
                        from core.views import TitleSearchMixin
                        from .models import Flavor
                        class FlavorListView(TitleSearchMixin, ListView):
                            model = Flavor
                        
                        
                        # add to stores/views.py
                        from django.views.generic import ListView
                        from core.views import TitleSearchMixin
                        from .models import Store
                        class IceCreamStoreListView(TitleSearchMixin, ListView):
                            model = Store
                        
                        1
                        2
                        3
                        4
                        5
                        6
                        7
                        8
                        9
                        10
                        11
                        12
                        13
                        14
                        15
                        16
                        17
                        18
                        19
                        20
                        21
                        22
                        23
                        24
                        25
                        26
                        27
                        {# form to go into stores/store_list.html template #}
                        <form action="" method="GET">
                        <input type="text" name="q" />
                        <button type="submit">search</button>
                        </form>
                        
                        {# form to go into flavors/flavor_list.html template #}
                        <form action="" method="GET">
                        <input type="text" name="q" />
                        <button type="submit">search</button>
                        </form>
                        
                        1
                        2
                        3
                        4
                        5
                        6
                        7
                        8
                        9
                        10
                        11

                        # form 相关3方包推荐:

                        PACKAGE TIP: Useful Form-Related Packages

                        • django-floppyforms for rendering Django inputs in HTML5.
                        • django-crispy-forms for advanced form layout controls. By default, forms are rendered with Twitter Bootstrap form elements and styles. This package plays well with django- floppyforms, so they are often used together.
                        • django-forms-bootstrap is a simple tool for rendering Django forms using Twitter Bootstrap styles. This package plays well with django-floppyforms but con..icts with django-crispy-forms.
                        #Django#Django最佳实践
                        上次更新: 2023/03/28, 16:27:19
                        最近更新
                        01
                        chromebox/chromebook 刷bios步骤
                        03-01
                        02
                        redis 集群介绍
                        11-28
                        03
                        go语法题二
                        10-09
                        更多文章>
                        Theme by Vdoing | Copyright © 2015-2024 DeanWu | 遵循CC 4.0 BY-SA版权协议
                        • 跟随系统
                        • 浅色模式
                        • 深色模式
                        • 阅读模式