TLDR Question: How do you make one crispy form with a ¿segmented?(not sure if this is considered inline) layout with multiple models(some related, some not).
I am trying to understand several things in Django: forms, formsets, nested forms, and crispy, and I've been at it for a while, and feel I am close, just need someone to help connect the dots. I'm not sure how to accomplish it without crispy, so I started down this path thinking crispy was the solution. Please correct if I am wrong, thanks :)
I would like one form (as in HTML form, not necessarily Django Form), that has a primary model with lots of fields, but with secondary/tertiary models in the middle of the primary fields. I am rather close to the layout, but can't seem to get the secondary/tertiary models to render in the middle of the layout, let alone compile without crispy/django erroring.
Here is a color-coded visual of what I am trying to attain
I assume I am wrong with at least one of the following:
- I am not calling the correct formfactory
- I am not properly using formsets
- I am not referencing the form fields to the correct model fields correctly in the layout of the form helper
- The layout is not possible, or I am applying the wrong code structure to get the result.
- I don't think I can call two forms directly as directly below, as they would not be nested/integrated
code for above list item (cant put a code block directly below
#I don't think this will achieve the integration/nested look I am aiming for
#views.py:
parent_form = ParentForm()
child_form = ChildForm()
render(template.html, {
"pform": parent_form,
"cform": child_form
})
#template.html:
<form>
{{ pform }}
{{ cform }}
</form>
Files For reference
models.py
#Black in the picture
class Truck(models.Model):
name = models.CharField(…)
…
#Blue in the picture
class QuickInspection(models.Model):
odometer = models.IntegerField(…)
… (created_at, user_cookie#who did it, …)
truck = models.ForeignKey(Truck)
-----
#These two are unrelated to the Truck in the DB, and I would prefer to keep it that way, if for at least to understand how to accomplish this
-----
#Red
class Tires(models.Model):
front_tire = models.CharField(…)
… (created_at, …)
truck = models.ForeignKey(Truck)
full_inspection = models.ForeignKey(FullInspection, blank=True, null=True) #optional, and if it has this foreign key, then I know the Tires were looked at in a full inspection. If not, then they were looked at in the quick inspection, without having a foreign key to the QuickInspection
#Green
class Brakes(models.Model):
front_axle = models.CharField(…)
…
createdAt = models.DateTimeField(auto_now_add=True)
truck = models.ForeignKey(Truck)
pm = models.ForeignKey(PM, blank=True, null=True)
full_inspection = models.ForeignKey(FullInspection, blank=True, null=True) #optional, same as full_inspection in Tires
views.py
def weeklyView(request, truckID):
# POST
if request.method == 'POST':
# Check forms for valid data and save or provide error
#return response
# GET
else:
#make each form individually?
quickForm = OHReadingForm(…)
tireForm = TireForm()
brakeForm = BrakeForm()
#Or import a formset and helper?
formset = ExampleFormSet()
helper = ExampleFormSetHelper()
response = render(request, 'trucks/weeklyInspection.html', {
'ohrForm': ohrForm,
'formset': formset,
'helper': helper,
'tireForm': tireForm,
'truck': truck,
})
forms.py
class QuickInspectionForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(QuickInspectionForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.form_method = 'post'
self.helper.form_action = 'quickInspectionURL'
self.helper.layout = Layout(
Div(
Div(
Fieldset(
'', # 'first arg is the legend of the fieldset',
'quickInspectionMetric1', #From QuickInspection.metric1
'quickInspectionMetric2', #From QuickInspection.metric2
'quickInspectionMetric3', #From QuickInspection.metric3
),
css_class="blue"
),
Div(
Fieldset(
'tireMetric1', #from Tire.metric1
'tireMetric2', #from Tire.metric2
css_class="red"
),
Div(
Fieldset(
'brakeMetric1', #from Brake.metric1
'brakeMetric2', #from Brake.metric2
css_class="green"
),
Div(
Fieldset(
'quickInspectionMetric4', #from QuickInspection.metric4
'quickInspectionMetric5', #from QuickInspection.metric5
css_class="blue"
),
),
Div(
FormActions(
Reset('reset', 'Reset'),
Submit('submit', 'Submit') #submit for all
)
),
)
class Meta:
model = QuickInspection
fields = [
'metric1','metric2','metric3','metric4','metric5',
'truck',
…,
]
ExampleFormSet = formset_factory(QuickInspectionForm, extra=1)
# Other failed attempts
# ExampleFormSet = inlineformset_factory(QuickInspectionForm, extra=1)
# ExampleFormSet = inlineformset_factory(QuickInspectionForm, TireForm, extra=1)
# ExampleFormSet = inlineformset_factory(QuickInspectionForm, TireForm, BrakeForm, extra=1)
class ExampleFormSetHelper(FormHelper):
def __init__(self, *args, **kwargs):
super(ExampleFormSetHelper, self).__init__(*args, **kwargs)
self.form_method = 'post'
self.form_tag = False
self.layout = Layout(…)
#Same as Brake Form
class TireForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(TCForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_method = 'post'
self.helper.form_action = 'tireURL'
self.helper.layout = Layout(…)
class Meta:
model = TireCondition
fields = [
'metric1', 'metric2', …
'truck',
]
JS fiddle for code repo. I don't know of a DJango-like Fiddle environment...