SlideShare une entreprise Scribd logo
1  sur  21
Télécharger pour lire hors ligne
Two Scoops of Django
Chapter 9 Common Patterns for Forms

Alfred
Forms
This chapter goes explicitly into the
concepts of forms, models and CBVs. There
are five common patterns.
Pattern 1: Simple ModelForm
with default Validators
Pattern 1: Simple ModelForm
with default Validators

• Auto generated a model form based on the
Flavor model.
Pattern 2: Custom Form Field
Validators in ModelForm
Pattern 2: Custom Form Field
Validators in ModelForm

• Customize your validator.
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?
Pattern 2: Custom Form Field
Validators in ModelForm(cont.)

• To create a customized form...
#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
Pattern 2: Custom Form Field
Validators in ModelForm(cont.)
#views.py	
from django.contrib import messages	
from django.views.generic import CreateView, UpdateView, DetailView	
from braces.views import LoginRequiredMixin	
from .models import Flavor	
from .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
Pattern 3: Overriding the clean
stage of Validation
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.
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
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
Pattern 4: Hacking Form Fields
Pattern 4: Hacking Form Fields

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

from django.db import models	
from 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})
Pattern 4: Hacking Form
Fields(cont.)

• Old style v.s. better style

from django import forms	
from models import IceCreamStore	
class 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
Pattern 4: Hacking Form
Fields(cont.)

• Much Better Style
from django import forms	
from 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")
Pattern 4: Hacking Form
Fields(cont.)

• Use it in view
from
from
from
from

django.views.generic import CreateView, UpdateView	
forms import IceCreamStoreCreateForm	
forms import IceCreamStoreUpdateForm	
models import IceCreamStore	

!
class IceCreamCreateView(CreateView):	
model=IceCreamStore	
form_class=IceCreamStoreCreateForm	

!
class IceCreamUpdateView(UpdateView):	
model=IceCreamStore	
form_class=IceCreamStoreUpdateForm
Pattern 5: Reusable Searching
Mixin View
Pattern 5: Reusable Searching
Mixin View

• Use a simple search view on multiple models
class 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	
{#form go into store#}	

class FlavorListView(TitleSearchMixin, ListView):	
model = Flavor	

!

class StoreListView(TitleSearchMixin, ListView):	
model = 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>
Thanks
Alfred

Contenu connexe

Tendances

Presentation technico-commercial-ruby-on-rails
Presentation technico-commercial-ruby-on-railsPresentation technico-commercial-ruby-on-rails
Presentation technico-commercial-ruby-on-rails
Novelys
 

Tendances (19)

Common Pitfalls Experienced in Java
Common Pitfalls Experienced in JavaCommon Pitfalls Experienced in Java
Common Pitfalls Experienced in Java
 
Validation
ValidationValidation
Validation
 
Repensando o Desenvolvimento Web com Ruby on Rails
Repensando o Desenvolvimento Web com Ruby on RailsRepensando o Desenvolvimento Web com Ruby on Rails
Repensando o Desenvolvimento Web com Ruby on Rails
 
What's New in newforms-admin
What's New in newforms-adminWhat's New in newforms-admin
What's New in newforms-admin
 
Working With The Symfony Admin Generator
Working With The Symfony Admin GeneratorWorking With The Symfony Admin Generator
Working With The Symfony Admin Generator
 
Presentation technico-commercial-ruby-on-rails
Presentation technico-commercial-ruby-on-railsPresentation technico-commercial-ruby-on-rails
Presentation technico-commercial-ruby-on-rails
 
The Django Book, Chapter 16: django.contrib
The Django Book, Chapter 16: django.contribThe Django Book, Chapter 16: django.contrib
The Django Book, Chapter 16: django.contrib
 
Specs2
Specs2Specs2
Specs2
 
Refatoração + Design Patterns em Ruby
Refatoração + Design Patterns em RubyRefatoração + Design Patterns em Ruby
Refatoração + Design Patterns em Ruby
 
Form demoinplaywithmysql
Form demoinplaywithmysqlForm demoinplaywithmysql
Form demoinplaywithmysql
 
Xml operations in odoo
Xml operations in odooXml operations in odoo
Xml operations in odoo
 
HTML Form Part 1
HTML Form Part 1HTML Form Part 1
HTML Form Part 1
 
Java Script
Java ScriptJava Script
Java Script
 
Django ORM - Marcin Markiewicz
Django ORM - Marcin Markiewicz Django ORM - Marcin Markiewicz
Django ORM - Marcin Markiewicz
 
Dig Deeper into WordPress - WD Meetup Cairo
Dig Deeper into WordPress - WD Meetup CairoDig Deeper into WordPress - WD Meetup Cairo
Dig Deeper into WordPress - WD Meetup Cairo
 
Django Forms: Best Practices, Tips, Tricks
Django Forms: Best Practices, Tips, TricksDjango Forms: Best Practices, Tips, Tricks
Django Forms: Best Practices, Tips, Tricks
 
Grain final border one
Grain final border oneGrain final border one
Grain final border one
 
Django Admin (Python meeutp)
Django Admin (Python meeutp)Django Admin (Python meeutp)
Django Admin (Python meeutp)
 
2013-06-25 - HTML5 & JavaScript Security
2013-06-25 - HTML5 & JavaScript Security2013-06-25 - HTML5 & JavaScript Security
2013-06-25 - HTML5 & JavaScript Security
 

Similaire à Two scoopsofdjango common patterns for forms

Testing for Pragmatic People
Testing for Pragmatic PeopleTesting for Pragmatic People
Testing for Pragmatic People
davismr
 
Ctools presentation
Ctools presentationCtools presentation
Ctools presentation
Digitaria
 
Introduction To Django (Strange Loop 2011)
Introduction To Django (Strange Loop 2011)Introduction To Django (Strange Loop 2011)
Introduction To Django (Strange Loop 2011)
Jacob Kaplan-Moss
 
Selenium with py test by Alexandr Vasyliev for Lohika Odessa Python TechTalks
Selenium with py test by Alexandr Vasyliev for Lohika Odessa Python TechTalksSelenium with py test by Alexandr Vasyliev for Lohika Odessa Python TechTalks
Selenium with py test by Alexandr Vasyliev for Lohika Odessa Python TechTalks
Lohika_Odessa_TechTalks
 

Similaire à Two scoopsofdjango common patterns for forms (20)

Django tricks (2)
Django tricks (2)Django tricks (2)
Django tricks (2)
 
Django Pro ORM
Django Pro ORMDjango Pro ORM
Django Pro ORM
 
Тестирование и Django
Тестирование и DjangoТестирование и Django
Тестирование и Django
 
Profile django
Profile djangoProfile django
Profile django
 
Testing for Pragmatic People
Testing for Pragmatic PeopleTesting for Pragmatic People
Testing for Pragmatic People
 
Mastering solr
Mastering solrMastering solr
Mastering solr
 
Django Heresies
Django HeresiesDjango Heresies
Django Heresies
 
Optimization in django orm
Optimization in django ormOptimization in django orm
Optimization in django orm
 
Tango with django
Tango with djangoTango with django
Tango with django
 
Lo nuevo de Django 1.7 y 1.8
Lo nuevo de Django 1.7 y 1.8Lo nuevo de Django 1.7 y 1.8
Lo nuevo de Django 1.7 y 1.8
 
Ctools presentation
Ctools presentationCtools presentation
Ctools presentation
 
Django forms
Django formsDjango forms
Django forms
 
BarcelonaJUG2016: walkmod: how to run and design code transformations
BarcelonaJUG2016: walkmod: how to run and design code transformationsBarcelonaJUG2016: walkmod: how to run and design code transformations
BarcelonaJUG2016: walkmod: how to run and design code transformations
 
An Introduction To Python - Functions, Part 1
An Introduction To Python - Functions, Part 1An Introduction To Python - Functions, Part 1
An Introduction To Python - Functions, Part 1
 
Wheels
WheelsWheels
Wheels
 
What's new in Django 1.7
What's new in Django 1.7What's new in Django 1.7
What's new in Django 1.7
 
Django Good Practices
Django Good PracticesDjango Good Practices
Django Good Practices
 
Pruebas unitarias con django
Pruebas unitarias con djangoPruebas unitarias con django
Pruebas unitarias con django
 
Introduction To Django (Strange Loop 2011)
Introduction To Django (Strange Loop 2011)Introduction To Django (Strange Loop 2011)
Introduction To Django (Strange Loop 2011)
 
Selenium with py test by Alexandr Vasyliev for Lohika Odessa Python TechTalks
Selenium with py test by Alexandr Vasyliev for Lohika Odessa Python TechTalksSelenium with py test by Alexandr Vasyliev for Lohika Odessa Python TechTalks
Selenium with py test by Alexandr Vasyliev for Lohika Odessa Python TechTalks
 

Dernier

Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
vu2urc
 

Dernier (20)

The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 

Two scoopsofdjango common patterns for forms

  • 1. Two Scoops of Django Chapter 9 Common Patterns for Forms Alfred
  • 2. Forms This chapter goes explicitly into the concepts of forms, models and CBVs. There are five common patterns.
  • 3. Pattern 1: Simple ModelForm with default Validators
  • 4. Pattern 1: Simple ModelForm with default Validators • Auto generated a model form based on the Flavor model.
  • 5. Pattern 2: Custom Form Field Validators in ModelForm
  • 6. Pattern 2: Custom Form Field Validators in ModelForm • Customize your validator.
  • 7. 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?
  • 8. Pattern 2: Custom Form Field Validators in ModelForm(cont.) • To create a customized form... #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
  • 9. Pattern 2: Custom Form Field Validators in ModelForm(cont.) #views.py from django.contrib import messages from django.views.generic import CreateView, UpdateView, DetailView from braces.views import LoginRequiredMixin from .models import Flavor from .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
  • 10. Pattern 3: Overriding the clean stage of Validation
  • 11. 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.
  • 12. 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
  • 13. 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
  • 14. Pattern 4: Hacking Form Fields
  • 15. Pattern 4: Hacking Form Fields • you have a ice cream store, some of fields are required, some are not. from django.db import models from 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})
  • 16. Pattern 4: Hacking Form Fields(cont.) • Old style v.s. better style from django import forms from models import IceCreamStore class 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
  • 17. Pattern 4: Hacking Form Fields(cont.) • Much Better Style from django import forms from 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")
  • 18. Pattern 4: Hacking Form Fields(cont.) • Use it in view from from from from django.views.generic import CreateView, UpdateView forms import IceCreamStoreCreateForm forms import IceCreamStoreUpdateForm models import IceCreamStore ! class IceCreamCreateView(CreateView): model=IceCreamStore form_class=IceCreamStoreCreateForm ! class IceCreamUpdateView(UpdateView): model=IceCreamStore form_class=IceCreamStoreUpdateForm
  • 19. Pattern 5: Reusable Searching Mixin View
  • 20. Pattern 5: Reusable Searching Mixin View • Use a simple search view on multiple models class 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 {#form go into store#} class FlavorListView(TitleSearchMixin, ListView): model = Flavor ! class StoreListView(TitleSearchMixin, ListView): model = 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>