Question

My title may be a little off-putting. I believe this is a common thing to do, just hard to describe. Okay, so I have two pretty simple models:

class Location(models.Model):
    location_name = models.CharField()
    street = models.CharField()
    city = models.CharField()
    state = models.CharField()

    zip_code = models.CharField()
    region = models.ForeignKey(Region)

    def __unicode__(self):
        return u'%s' % (self.location_name)

    class Meta:
        verbose_name = "Location"
        verbose_name_plural = "Locations"



class Region(models.Model):
    """
        Regions are arbitrarily set on location by users. This is for 
        them to be able to segment/organize their Locations. Region is
        merely a tag for description purposes.
    """

    region_name = models.CharField(max_length=75)


    def __unicode__(self):
        return u'%s' % (self.region_name)

    class Meta:
        verbose_name = "Region"
        verbose_name_plural = "Regions"

I have built a modelform that looks like this:

class locationForm(forms.ModelForm):
    class Meta:
        model = Location
        fields = (
            'location_name',
            'street',
            'city',
            'state',
            'zip_code',
            'region'
        )

My main concern involves regions: If a user is filling out a form for the first time, they won't have any regions to pick from via foreignkey. While a user creates a Location I want 1. an instance of location and an instance of region to be created 2. the recently created region to be assigned to the location instance. Keep in mind that the second time the user fills the form, the form needs to be able to display all past regions as viable options as well as make it the case that a new one can be create.

Can anyone shed some light on how to tackle this issue?

Was it helpful?

Solution

Another way is to make a common default Region called 'New Region'. When you inspect the POST-data, send the user to a create-new-region-view if the selected region is 'New Region'.

This will be useful when the user want to create a new region when creating a location, independently of if there are any existing regions created already.


I wrote a simple example for you, see below. The idea is to add a hidden field to RegionForm, so that the created Location can be updated with the new region after the new region has been created. I'm not sure if this is the best way to solve the problem, but it works at very least (I set up a testing environment to test it).

Make sure that you create a 'Create New Region' Region first, and set CREATE_NEW_REGION_ID accordingly.

views.py

from django.http.response import HttpResponseRedirect
from django.shortcuts import render
from add_location.forms import LocationForm, RegionForm


# The ID of the 'Create New Region' region
CREATE_NEW_REGION_ID = 1


def add_location(request):
    if request.method == 'POST':
        display_form = LocationForm(request.POST)
        region_form = RegionForm(request.POST)

        # Check if the form is a valid LocationForm
        if display_form.is_valid():
            location = display_form.save()
            # If region is the default 'Create new region' region, render the
            # page with a new RegionForm
            if location.region.id == CREATE_NEW_REGION_ID:
                # Note that the location is saved above, so if the region isn't 
                # created in the next form, its region will stay 
                # 'Create New Region'
                display_form = RegionForm(initial={'location': location})
            else:
                return HttpResponseRedirect('/thanks/')

        # If not a valid LocationForm, check if it is a valid RegionForm
        elif region_form.is_valid():
                # Save the region, get the location and update the
                # region of the location
                region = region_form.save()
                location = region_form.cleaned_data['location']
                location.region = region
                location.save()
                return HttpResponseRedirect('/thanks/')
    else:
        display_form = LocationForm()

    return render(request, 'form.html', {'form': display_form})


def thanks(request):
    return render(request, 'thanks.html')

forms.py

from django import forms
from add_location.models import Location, Region


class LocationForm(forms.ModelForm):
    class Meta:
        model = Location


class RegionForm(forms.ModelForm):
    location = forms.ModelChoiceField(Location.objects.all(),
                                      widget=forms.HiddenInput())

    class Meta:
        model = Region

forms.html

<!DOCTYPE html>
<html>
<head>
    <title>Thanks</title>
</head>
<body>
    <form action="/add/location/" method="post">{% csrf_token %}
        {{ form.as_p }}
        <input type="submit" value="Submit" />
    </form>
</body>
</html>

urls.py

from django.conf.urls import patterns, include, url

from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
    # Examples:
    # url(r'^$', 'sampledjango.views.home', name='home'),
    # url(r'^blog/', include('blog.urls')),

    url(r'^admin/', include(admin.site.urls)),
    url(r'^add/location/', 'add_location.views.add_location'),
    url(r'^thanks/', 'add_location.views.thanks'),
)

OTHER TIPS

One way would be to use two forms, one for the Location the other for Region. Add some javascript to the template to show the CreateRegionForm when the user clicks a button/link signaling they want to add one.

Then on POST you'll want to determine if the region has been supplied. If it has, then create it and set the initial value for the location form. I would do something like:

region_form = RegionForm(request.POST)
region = None
if request.POST.get('region_name') and region_form.is_valid():
    # Don't create the object in case there's a validation error in location_form
    region = region_form.save(commit=False)
location_form = LocationForm(request.POST, initial={'region': region})
if location_form.is_valid():
    if not location_form.instance.region.id:
       # Need to save the region for the case if it was created
       location_form.instance.region.save()
    location = location_form.save()
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top