Django:当场在表单中创建一个forgeinkey。

时间:2014-05-08 18:37:39

标签: python django django-models django-forms

我的头衔可能有些令人不快。我相信这是常见的事情,很难描述。好的,所以我有两个非常简单的模型:

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"

我已经构建了一个如下所示的模型:

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

我主要关心的是区域:如果用户第一次填写表单,他们将无法通过外键选择任何区域。当用户创建我想要的位置时1.位置的实例和要创建的区域的实例2.最近创建的要分配给位置实例的区域。请记住,第二次用户填写表单时,表单需要能够将所有过去的区域显示为可行的选项,并使其成为可以创建新区域的情况。

任何人都可以解释如何解决这个问题吗?

2 个答案:

答案 0 :(得分:2)

一种方法是使用两个表单,一个用于Location,另一个用于Region。当用户单击要添加的按钮/链接信号时,向模板添加一些javascript以显示CreateRegionForm。

然后在POST上你将要确定是否已经提供了该区域。如果有,则创建它并设置位置表单的初始值。我会做类似的事情:

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()

答案 1 :(得分:2)

另一种方法是创建一个名为Region的公共默认'New Region'。检查POST数据时,如果所选区域为'New Region',则将用户发送到 create-new-region -view。

当用户想要在创建位置时创建新区域时,这将非常有用,与是否已创建任何现有区域无关。


我为你写了一个简单的例子,见下文。我们的想法是向RegionForm添加一个隐藏字段,以便在创建新区域后,可以使用新区域更新创建的Location。我不确定这是否是解决问题的最佳方法,但它至少可以工作(我设置了一个测试环境来测试它)。

请务必先创建'创建新区域' Region,然后相应地设置CREATE_NEW_REGION_ID

<强> 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'),
)