# How to DRY up my forms.py?

I have two ModelForms that are the same, except that one of them has its form layout built in a view and one has a submit button. These are pretty long and I have a ton of duplicate code. I have tried subclassing, but I don't understand it well enough to make it work right. I end up unable to override things.

class SurveyForm(forms.ModelForm):

nsf_CHOICES = (
(1, 'Never',),
(2, '',),
(3, 'Sometimes',),
(4, '',),
(5, 'Frequently',),
)

nmv_CHOICES = (
(1, 'Not Descriptive'),
(2, ''),
(3, ''),
(4, 'Moderately Descriptive'),
(5, ''),
(6, ''),
(7, 'Very Descriptive'),
)

class Meta:
model = Survey
exlude = 'cei_total','aggbs_total','si_total','cfiab_total','cfimb_total'

def __init__(self, *args, **kwargs):

self.helper = FormHelper()
self.form_method = 'post'
self.helper.form_tag = False
super(SurveyForm, self).__init__(*args, **kwargs)

nsf_CHOICES = (
(1, 'Never',),
(2, '',),
(3, 'Sometimes',),
(4, '',),
(5, 'Frequently',),
)

nmv_CHOICES = (
(1, 'Not Descriptive'),
(2, ''),
(3, ''),
(4, 'Moderately Descriptive'),
(5, ''),
(6, ''),
(7, 'Very Descriptive'),
)

class Meta:
model = Survey
exlude = 'cei_total','aggbs_total','si_total','cfiab_total','cfimb_total'

def __init__(self, *args, **kwargs):

self.helper = FormHelper()
self.form_method = 'post'
self.helper.form_action = ''
self.helper.layout = Layout(
Field('student', type='hidden'),
Field('surveyset', type='hidden'),
Field('behavior_type', type='hidden'),
Field('ranking', type='hidden'),
Fieldset('Critical Events Index',
HTML("""
<p>Check each behavior from the list below that the child has exhibited during this school year. Complete this using your knowledge of <b>{{ student }}</b> during this school year.</p>
"""),
'cei_0','cei_1','cei_2','cei_3','cei_4','cei_5','cei_6','cei_7','cei_8','cei_9','cei_10','cei_11','cei_12','cei_13','cei_14','cei_15',
),

Fieldset('Aggressive Behavior Scale',
HTML("""
<p>The numbers one through five are used to show the estimate of the frequency with which each item occurs. Choose the number that best represents the amount of times this behavior happens. Complete this scale using your knowledge of <b>{{ student }}</b> during this school year.</p>
"""),'aggbs_0','aggbs_1','aggbs_2','aggbs_3','aggbs_4','aggbs_5','aggbs_6','aggbs_7',
),

Fieldset('Social Interaction',
HTML("""
<p>The numbers one through seven are used to show the estimate of the frequency with which each item occurs. Choose the number that best represents the amount of times this behavior happens. Complete this scale using your knowledge of <b>{{ student }}</b> during this school year.</p>
"""),'si_0','si_1','si_2','si_3','si_4','si_5','si_6','si_7',
),
HTML("""
<p>The numbers one through five are used to show the estimate of the frequency with which each item occurs. Choose the number that best represents the amount of times this behavior happens. Complete this scale using your knowledge of <b>{{ student }}</b> during this school year.</p>
"""), 'cfiab_0','cfiab_1','cfiab_2','cfiab_3','cfiab_4','cfiab_5','cfiab_6','cfiab_7',
),
HTML("""<p>The numbers one through five are used to show the estimate of the frequency with which each item occurs. Choose the number that best represents the amount of times this behavior happens. Complete this scale using your knowledge of <b>{{ student }}</b> during this school year.</p>
"""),
'cfimb_0','cfimb_1','cfimb_2','cfimb_3','cfimb_4','cfimb_5','cfimb_6','cfimb_7','cfimb_8',
),
)


The reason I have both these is that one is used in a formset and the other is used standalone. I am also using crispy forms, hence the FormHelper().

• Can you please wrap your code at 80 columns as per PEP8? It's hard to read at the moment with all the scrolling. – Ruslan Osipov Apr 5 '14 at 17:16

Here's an approach.

Start out by defining a empty class, say, FormTemplate that inherits from forms.ModelForm and let both SurveyForm and UpdateSurveyForm inherit from FormTemplate. Make sure that works. I guess FormTemplate will need an __init__() that forwards super(...).__init__() calls to forms.ModelForm.

Then, move nsf_CHOICES into FormTemplate and out of {Update,}SurveyForm. Make sure that works.

Move nvm_CHOICES into FormTemplate and out of {Update,}SurveyForm. Make sure that works.

Lather, rinse, and repeat until you've pulled all the common stuff that out you can out of the child classes and into FormTemplate.

Use git (or some other VCS) and commit every time you get things working before doing the next piece. That way, you'll always have a working version to back up to if you need to.

Also, as Ruslan suggests, wrapping your lines at 80 columns would make your code much more readable.

Also, it's generally considered bad practice to use exclude: if new fields are added to the model they will be rendered for the client by default. It's much safer to use explicitly whitelist fields using the fields attribute of the meta class.