views:

104

answers:

2

I have a Model that looks something like this:

class Business(models.Model):
    name = models.CharField('business name', max_length=100)
    # ... some other fields
    emails = models.ManyToManyField(Email, null=True)
    phone_numbers = models.ManyToManyField(PhoneNumber, null=True)
    urls = models.ManyToManyField(URL, null=True)

and a corresponding ModelForm:

class BusinessContactForm(forms.ModelForm):
    emails = forms.CharField(widget=forms.Textarea(attrs={'rows':4,'cols':32}))
    phone_numbers = forms.CharField(widget=forms.Textarea(attrs={'rows':4,'cols':32}))
    urls = forms.CharField(widget=forms.Textarea(attrs={'rows':4,'cols':32}))

    class Meta:
        model = Business
        fields = ['emails', 'phone_numbers', 'urls',]

My question: What is the best way to load the existing emails, phone_numbers, and urls into the Textarea widgets when presenting the form (one per line in their respective widgets)?

Then, after the form has been modified and submitted, what is the best way to make sure to add any new emails, numbers, or urls (m2m relationships) and remove any that are no longer in the list (also making sure not to add duplicates)?

+1  A: 

This is not directly an answer to your question. It is more a suggestion to re-think your data model.

It looks like your BusinessContactForm presents textarea widgets to insert multiple rows into the database. I would not use a Textarea widget for multiple items of more restricted type: I'd enter phone numbers with a phone number widget, URLs with a URL widget, and emails with an email widget.

A business contact is really a person who works for a company and has an email address and phone number, correct? So why not model the business contact like that and have a foreign key to the business?

That's more of the approach I would take.

hughdbrown
The reason I've done it this way is because the contact information may not direct to just one person - for example the e-mail address [email protected] or the phone number 1-800-busines both belong to the business itself and not a particular person (what if they were replaced?). What I had in mind was to pass each line into a field of the respective type for validation, but the problem of maintaining that link to the DB object (as a ModelForm does with the underlying model) when trying to save the items after validation remains.
John Debs
So I moved each field out to separate tables with many-to-one relationships. See my comment on the answer below for details.
John Debs
+1  A: 

This really isn't a good way to do it. Dealing with related items on forms is what formsets are for.

Instead of defining the related fields as extra fields on the BusinessForm model, use a standard form for a contact, with email, phone and url. Then pass this into the modelformset_factory to create an inline formset for your BusinessContact form.

Daniel Roseman
I had thought about using formsets but it seemed like this would be a simpler UI and cleaner code overall (assuming I could get it to work as I envisioned it - which is rarely the case).That said, I had tried formsets but didn't like that I had to create one for each of the three items in the view (email, phone, url), and then validate and handle data from each as well. You mention an "inline" formet for the BusinessContact form - is that a special type of formset? If so, could you elaborate a bit? Thanks!
John Debs
I should also note: I didn't create one formset with all three items because the user should be able to specify different numbers of each (maybe one or two URLS, a few phone numbers, and several email addresses).
John Debs
So I researched inline formsets after you mentioned them (I had searched the documentation several times and managed to miss that part) and they seem to take care of all the complexities I need...I'll have to live with creating one formset for each related field and moving them to many-to-one relationships. Thanks for the help.
John Debs