Marco Alabruzzo
Full stack developer @ Growth Street
Marco Alabruzzo
http://marcoala.com - marco.alabruzzo@gmail.com
London Django Meetup Group
13 December 2016
I like my code like I like my whisky, DRY
John - developer
A user interface is like a joke.
If you have to explain it, it’s not that good
Bob - product manager
# my_app.models.py
from django.db import models
from django.core import validators
class UserProfile(models.Model):
name = models.CharField()
email = models.EmailField()
password = models.CharField(max_length=50)
company_name = models.CharField()
company_number = models.CharField(
max_length=10,
validators=[
validators.RegexValidator(
regex='^(SC|)[0-9]{8}$',
message='This is not a correct UK company number'
),
]
# my_app.forms.py
from django import forms
from my_app.models import UserProfile
class UserProfileForm(models.ModelForm):
class Meta:
model = UserProfile
fields = ['name', 'email', 'password', 'company_name', 'company_number']
widgets = {
'password': forms.PasswordInput(),
}
We want to add a new field, telephone number. It must be validated as with a max length of 11 characters.
Of course, the new field is required for new users, but we don’t have this data for the old ones,
so admins should be able to leave the field blank
Bob - product manager
# my_app.models.py
from django.db import models
from django.core import validators
class UserProfile(models.Model):
name = models.CharField()
email = models.EmailField()
password = models.CharField(max_length=50)
company_name = models.CharField()
company_number = models.CharField(
max_length=10,
validators=[
validators.RegexValidator(
regex='^(SC|)[0-9]{8}$',
message='This is not a correct UK company number'
),
]
phone_number = models.CharField(max_length=11, null=True, blank=True)
# my_app.forms.py
from django import forms
from my_app.models import UserProfile
class AdminUserProfileForm(models.ModelForm):
class Meta:
model = UserProfile
fields = ['name', 'email', 'password', 'company_name', 'company_number', 'phone_number']
widgets = {
'password': forms.PasswordInput(),
}
class UserProfileForm(AdminUserProfileForm):
phone_number = forms.CharField(max_length=11, required=True)
The code is not 100% DRY, but is still pretty good
John - developer
More and more of our customer are asking to have more than one user for the same company
While our designers work on the new feature can you prepare the database to accommodate it?
Bob - product manager
# my_app.models.py
from django.db import models
from django.core import validators
class UserProfile(models.Model):
name = models.CharField()
email = models.EmailField()
password = models.CharField(max_length=50)
company = models.ForeignKey(CompanyProfile)
class CompanyProfile(models.Model):
company_name = models.CharField()
company_number = models.CharField(
max_length=10,
validators=[
validators.RegexValidator(
regex='^(SC|)[0-9]{8}$',
message='This is not a correct UK company number'
),
]
phone_number = models.CharField(max_length=11, null=True, blank=True)
# my_app.forms.py
from django import forms
class AdminUserProfileForm(forms.Form):
name = forms.CharField()
email = forms.EmailField()
password = forms.CharField(max_length=50)
company_name = forms.CharField()
company_number = forms.CharField(
max_length=10,
validators=[
validators.RegexValidator(
regex='^(SC|)[0-9]{8}$',
message='This is not a correct UK company number'
),
]
phone_number = forms.CharField(max_length=11, required=False)
def save(self):
# define save logic here
class UserProfileForm(forms.Form):
phone_number = forms.CharField(max_length=11, required=True)
There is no way I can make this DRY
John - sad developer
I have to replicate ALL the field definitions between the Model and the Form
Maybe I can just become product manager...
# my_app.forms.py
from django import forms
from field_builder.forms import FieldBuilder
from my_app.models import UserProfile, CompanyProfile
class AdminUserProfileForm(models.Form):
name = FieldBuilder(UserProfile, 'name')
email = FieldBuilder(UserProfile, 'email')
password = FieldBuilder(UserProfile, 'password', widget=forms.PasswordInput())
company_name = FieldBuilder(CompanyProfile, 'company_name')
company_number = FieldBuilder(CompanyProfile, 'company_number')
phone_number = FieldBuilder(CompanyProfile, 'company_number')
def save(self):
# you have to define your own save method now
# this is Form not a ModelForm
class UserProfileForm(AdminUserProfileForm):
phone_number = FieldBuilder(CompanyProfile, 'company_number', required=True)
What if we could be a ModelForm field by field?
# field_builder/forms.py
class FieldBuilder(object):
def __new__(cls, model, field_name, **kwargs):
model_field = model._meta.get_field(field_name)
return model_field.formfield(**kwargs)
exposes the internal functionalities of the ModelForm, allowing you to generate a form field based on a model field
and allow you to override a single field parameter
(Questions?)