Login

inline forms for deeply nested models

Author:
cdrandin
Posted:
October 15, 2017
Language:
Python
Version:
Not specified
Tags:
django django-forms
Score:
0 (after 0 ratings)

I had a problem trying to display my model would have a foreign key and that model would have one too etc.

Now there was a point I wanted to display the foreign keys of that field and display its fields and so on so forth.

This pretty much expands the models by getting the base form that worked best for me.

It is intended to only work alongside Forms. I haven't been able to get it to work with ModelForm.

Example usage:

forms.py

class AddressForm(forms.Form):
    address_0 = forms.CharField(label="address", max_length=64)
    address_1 = forms.CharField(
        label="address cont'd", max_length=64, required=False)
    city = forms.CharField(max_length=64)
    state = USStateField(widget=USStateSelect) # django_localflavor_us.forms
    zip_code = USZipCodeField(label='zipcode') # django_localflavor_us.forms


class ContactInfoForm(ForeignKeyFormMixin, forms.Form):
    name = forms.CharField(max_length=50)
    # address = model.ForeignKey(Address) # is a foreignkey in my model for Address
    phone = PhoneNumberField() # phonenumber_field.formfields (irrelevant could very well be forms.CharField)
    fax = PhoneNumberField(required=False) # phonenumber_field.formfields (irrelevant could very well be forms.CharField)
    email = forms.EmailField()
    foreign_keys = {'address': AddressForm} # foreign forms I want to introduce, key acts as a related_name

    def __init__(self, *args, **kwargs):
        super(ContactInfoForm, self).__init__(*args, **kwargs)


class GenerationForm(ForeignKeyFormMixin, forms.Form):
    company = forms.CharField(max_length=50)
    code = forms.CharField(max_length=50, required=False)

    # contact = model.ForeignKey(ContactInfo) # is a foreignkey in my model for Contact
    # facility_address = model.ForeignKey(AddressForm, related_name='facility') # is a foreignkey in my model for Address
    # mailing_address = model.ForeignKey(AddressForm, related_name='mailing') # is a foreignkey in my model for Address
    foreign_keys = {'contact': ContactInfoForm,
                    'facility_address': AddressForm,
                    'mailing_address': AddressForm}



view.py

def generation_create_view(self):
    if self.request.method == 'POST':
        generator_form = GenerationForm(self.request.POST)
        if generator_form.is_valid():
            cleaned_data = generator_form.cleaned_data

            (contact_address, created) = Address.objects.get_or_create(
                address_0=cleaned_data['contact_address_address_0'], # notice naming. trying to keep it orgnized as possible and reuse the "foreign key" you want to expand
                address_1=cleaned_data['contact_address_address_1'],
                city=cleaned_data['contact_address_city'].title(),
                state=cleaned_data['contact_address_state'][:2].upper(),
                zip_code=cleaned_data['contact_address_zip_code'],
            )
            print contact_address

            (contact_info, created) = ContactInfo.objects.get_or_create(
                name=cleaned_data['contact_name'],
                address=contact_address,
                phone=cleaned_data['contact_fax'],
                email=cleaned_data['contact_email'],
            )
            print contact_info
            # ...
            # (assuming you have created other models as above)

            (generator, created) = Generator.objects.get_or_create(
                contact=contact_info,
                company=cleaned_data['company'],
                facility_address=facility_address,
                mailing_address=mailing_address,
                code=cleaned_data['code'],
            )
           return redirect('to some where')
    else:
        generator_form = GenerationForm()

    return render(request, 'generation_create.html', {'generator_form': generator_form, })




generator_form.html

# assuming your standard form tags are setup `<form class="form"...>...`. you would access form and display as follows
# I am using https://django-bootstrap.readthedocs.io/en/latest/index.html
# to help display forms in bootstrap

    <p class="lead">Contact</p>
    {% bootstrap_form generator_form.contact %} # can also just do {{ generator_form.contact }}

    {% bootstrap_field generator_form.company %} # can also just do {{ generator_form.company }}

    <p class="lead">Facility:</p>
    {% bootstrap_form generator_form.facility_address %} # can also just do {{ generator_form.facility_address }}

    <p class="lead">Mailing:</p>
    {% bootstrap_form generator_form.mailing_address %} # can also just do {{ generator_form.mailing_address }}

    {% bootstrap_field generator_form.code %} # can also just do {{ generator_form.code }}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class ForeignKeyFormMixin(object):

    def __init__(self, *args, **kwargs):
        super(ForeignKeyFormMixin, self).__init__(*args, **kwargs)
        for k, v in self.foreign_keys.items():
            f = collections.OrderedDict()
            for kk, vv in v().fields.items():
                self.fields['{}_{}'.format(k, kk)] = vv
                if not self.fields['{}_{}'.format(k, kk)].label:
                    self.fields['{}_{}'.format(k, kk)].label = kk.replace(
                        '_', ' ').title()
                f['{}_{}'.format(k, kk)] = self.fields['{}_{}'.format(k, kk)]

            v_form = v(*args, **kwargs)
            v_form.fields = f
            setattr(self, k, v_form)

More like this

Comments

Please login first before commenting.