Two scoopsofdjango common patterns for forms

21
Two Scoops of Django Chapter 9 Common Patterns for Forms Alfred

Transcript of Two scoopsofdjango common patterns for forms

Page 1: Two scoopsofdjango   common patterns for forms

Two Scoops of DjangoChapter 9 Common Patterns for Forms

Alfred

Page 2: Two scoopsofdjango   common patterns for forms

Forms

This chapter goes explicitly into the concepts of forms, models and CBVs. There are five common patterns.

Page 3: Two scoopsofdjango   common patterns for forms

Pattern 1: Simple ModelForm with default Validators

Page 4: Two scoopsofdjango   common patterns for forms

Pattern 1: Simple ModelForm with default Validators

• Auto generated a model form based on the Flavor model.

Page 5: Two scoopsofdjango   common patterns for forms

Pattern 2: Custom Form Field Validators in ModelForm

Page 6: Two scoopsofdjango   common patterns for forms

Pattern 2: Custom Form Field Validators in ModelForm

• Customize your validator.

Page 7: Two scoopsofdjango   common patterns for forms

Pattern 2: Custom Form Field Validators in ModelForm(cont.)

• To use it

•what if we wanted to use validate_tasty() in just forms? •what if we wanted to assign it to other fields?

Page 8: Two scoopsofdjango   common patterns for forms

Pattern 2: Custom Form Field Validators in ModelForm(cont.)

• To create a customized form...#forms.pyfrom django import formsfrom core.validators import validate_tastyfrom .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

Page 9: Two scoopsofdjango   common patterns for forms

Pattern 2: Custom Form Field Validators in ModelForm(cont.)

#views.pyfrom django.contrib import messagesfrom django.views.generic import CreateView, UpdateView, DetailViewfrom braces.views import LoginRequiredMixinfrom .models import Flavorfrom .forms import FlavorForm!class FlavorActionMixin(object): model = Flavor @property def action(self): msg = "{0} is missing action.".format(self.__class__) raise NotImplementedError(msg)! def form_valid(self, form): msg = "Flavor {0}!".format(self.action) messages.info(self.request, msg) return super(FlavorActionMixin, self).form_valid(form)!class FlavorCreateView(LoginRequiredMixin, FlavorActionMixin, CreateView): model = Flavor action = "created" form_class = FlavorForm!class FlavorUpdatedView(LoginRequiredMixin, FlavorActionMixin, UpdateView): model = Flavor action = "updated" form_class = FlavorForm!class FlavorDetailView(DetailView): model = Flavor

Page 10: Two scoopsofdjango   common patterns for forms

Pattern 3: Overriding the clean stage of Validation

Page 11: Two scoopsofdjango   common patterns for forms

Pattern 3: Overriding the clean stage of Validation

• Multi-field validation

• Validation involving existing data from the database that has already been validated.

clean() and clean<field_name>()

• clean() method is the place to validate two or more fields against each other, since it’s not specific to any one particular field.

• The clean validation stage is a better place to attach validation against persistent data.

Page 12: Two scoopsofdjango   common patterns for forms

Pattern 3: Overriding the clean stage of Validation(cont.)

• We are going to check the remaining amount is enough or not...

class IceCreamOrderForm(forms.ModelForm): slug = forms.ChoiceField("Flavor") toppings = forms.CharField()! def __init__(self, *args, **kwargs): super(IceCreamOrderForm, self).__init__(*args, **kwargs) self.fields["slug"].choices = [ (x.slug, x.title) for x in Flavor.objects.all() ]! def clean_slug(self): slug = self.cleaned_data["slug"] if Flavor.objects.get(slug=slug).scoops_remainin <= 0: msg = u"sorry, we are out of flavor" raise forms.ValidationError(msg) return slug

Page 13: Two scoopsofdjango   common patterns for forms

Pattern 3: Overriding the clean stage of Validation(cont.)

• And then check multiple fields..

class IceCreamOrderForm(forms.ModelForm): ... def clean(self): cleaned_data = super(IceCreamOrderForm, self).clean() slug = cleaned_data.get("slug", "") toppings = cleaned_data.get("toppings", "") 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

Page 14: Two scoopsofdjango   common patterns for forms

Pattern 4: Hacking Form Fields

Page 15: Two scoopsofdjango   common patterns for forms

Pattern 4: Hacking Form Fields

from django.db import modelsfrom django.core.urlresolvers import reverse# Create your models here.!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})

• you have a ice cream store, some of fields are required, some are not.

Page 16: Two scoopsofdjango   common patterns for forms

Pattern 4: Hacking Form Fields(cont.)

• Old style v.s. better stylefrom django import formsfrom models import IceCreamStoreclass IceCreamStoreUpdateForm(forms.ModelForm):! phone = forms.CharField(required=True) #duplicate description = forms.TextField(required=True) #duplicate! class Meta: model = IceCreamStore

class IceCreamStoreUpdateForm(forms.ModelForm):! class Meta: model = IceCreamStore! def __init__(self, *args, **kwargs): super(IceCreamStoreUpdateForm, self).__init__(*args, **kwargs) self.fields["phone"].required=True self.fields["description"].required=True

Page 17: Two scoopsofdjango   common patterns for forms

Pattern 4: Hacking Form Fields(cont.)

• Much Better Stylefrom django import formsfrom models import IceCreamStore!class IceCreamStoreCreateForm(forms.ModelForm): class Meta: model = IceCreamStore field = ("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: model = IceCreamStore fields = ("title", "block_address", "phone", "description")!

Page 18: Two scoopsofdjango   common patterns for forms

Pattern 4: Hacking Form Fields(cont.)

• Use it in viewfrom django.views.generic import CreateView, UpdateViewfrom forms import IceCreamStoreCreateFormfrom forms import IceCreamStoreUpdateFormfrom models import IceCreamStore!class IceCreamCreateView(CreateView): model=IceCreamStore form_class=IceCreamStoreCreateForm!class IceCreamUpdateView(UpdateView): model=IceCreamStore form_class=IceCreamStoreUpdateForm

Page 19: Two scoopsofdjango   common patterns for forms

Pattern 5: Reusable Searching Mixin View

Page 20: Two scoopsofdjango   common patterns for forms

Pattern 5: Reusable Searching Mixin View

• Use a simple search view on multiple modelsclass TitleSearchMixin(object): def get_queryset(self): queryset = super(TitleSearchMixin, self).get_queryset()! q = self.request.GET.get("q") if q: return queryset.filter(title__icontains=q) return queryset!class FlavorListView(TitleSearchMixin, ListView): model = Flavor!class StoreListView(TitleSearchMixin, ListView): model = Store

{#form go into store#}<form action="" method="GET"> <input type="text" name="q"/> <button type="submit">search</button></form>{#form go into flavor#}<form action="" method="GET"> <input type="text" name="q"/> <button type="submit">search</button></form>

Page 21: Two scoopsofdjango   common patterns for forms

ThanksAlfred