Django ModelForms:在表单中播种FK相关字段

时间:2014-01-27 01:44:09

标签: python django forms django-forms django-crispy-forms

我有一个Workshop Django应用。每个Workshop可以通过相关的WorkshopAttendee模型(下面简化)有多个与会者。我在基于类的视图中使用Django的ModelForm,在forms.py我正在使用crispy-forms

models.py(相关部分)

class Workshop(models.Model):
    title = models.CharField(max_length=100)
    information = models.TextField()
    location = models.TextField()

class WorkshopAttendee(models.Model):
    workshop = models.ForeignKey(Workshop)
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)

views.py(相关部分)

from django.views.generic.edit import FormView
from workshop.forms import WorkshopAttendeeForm

class WorkshopAttendeeFormView(FormView):

    def form_valid(self, form):
        # Clean the data
        form_data = form.cleaned_data
        form.save(commit=False)
        return super(WorkshopAttendeeFormView, self).form_valid(form)

forms.py

from django.forms import ModelForm
from workshop.models import WorkshopAttendee
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, HTML, Field, \
    Fieldset, Button, Hidden, Submit, Reset
from crispy_forms.bootstrap import FormActions

# Create the form class
class WorkshopAttendeeForm(ModelForm):
    def __init__(self, *args, **kwargs):
        # Crispy form Layouts, Fieldsets, etc
        super(WorkshopAttendeeForm, self).__init__(*args, **kwargs)

    class Meta:
        model = WorkshopAttendee

urls.py(相关部分)

urlpatterns = patterns('',
    url(r'^(?P<year>\d{4})/(?P<month>\d{2})/(?P<slug>[\w\-.]+)/(?P<action>[\w\-.]+)/$',
        WorkshopAttendeeFormView.as_view(
            form_class=WorkshopAttendeeForm,
            success_url="success/",
            template_name='workshop/workshop_registration.html',
        ), name='workshop-attendee-register'
    ),
    url(r'^(?P<year>\d{4})/(?P<month>\d{2})/(?P<slug>[\w\-.]+)/$',
        WorkshopDetailView.as_view(
            context_object_name='workshop_detail',
            queryset=Workshop.objects.select_related(),
            template_name='workshop/workshop_detail.html',
        ), name='workshop-detail'
    ),
)

我的问题是,如何在隐藏的表单字段中使用 workshop_id (即FK关系)播种表单?显然因为表格还没有提交,所以还没有FK关系。但是在网址中,我有Workshop slug kwarg 。我可以在每个研讨会的基础上将workshop_id硬编码为Hidden()脆片形式字段,但这完全没有问题。有任何想法吗?我不认为我可以在 urls.py 中使用模型上的select_related()prefetch_related()方法,所以也许我必须以某种方式将两个模型都放到表单视图中?

我觉得这不是一个边缘情况,我相信其他人也有类似的应用工作流程。

提前致谢。

更新

经过进一步研究后,似乎可以使用Django Formsets完成此操作。还没弄清楚究竟是怎么回事.....暗示欢迎。

2 个答案:

答案 0 :(得分:2)

你不需要传递PK - 你已经在你的URL中将它作为slug。

所以我们假设这是您的网址:http://example.com/workshops/awesome-workshop-slug/sign_in/ 您的urls.py应如下所示:

url(r'^workshop/(?P<workshop_slug>\w+)/sign_in/$',
        # ../workshops/awesome-workshop-slug/sign_in/
        view = 'workshop_signin',
        name = 'workshop-signin',
    ),

好的,在您的views.py中,您可以执行此操作:

@login_required
def workshop_signin(request, workshop_slug, template='workshop/sign_in.html'):
    """Register user to workshop."""
    form = WorkshopForm()
    workshop = Workshop.objects.filter(slug=workshop_slug)[0]

    if request.method == 'POST':
        form = WorkshopForm(request.POST, instance=workshop)
        if form.is_valid():
            messages.info(request, 'Yay!')


    kwargs = {
        'workshop_form': form,
    }
    return render_to_response(template, kwargs, context_instance=RequestContext(request))

*未经测试的快速和脏代码

答案 1 :(得分:0)

事实证明我过于复杂了。

我需要做的就是将Django的GCBV form_valid的{​​{1}}方法修改为:

<强>车间/ views.py

FormView

这基本上不会在提交时保存表单,而是覆盖它并首先使用相关from django.views.generic.edit import FormView from workshop.models import Workshop, WorkshopAttendee from workshop.forms import WorkshopAttendeeForm from django.http import HttpResponseRedirect class WorkshopAttendeeFormView(FormView): def form_valid(self, form): self.object = form.save(commit=False) self.object.workshop = Workshop.objects.filter(slug=self.kwargs['slug'])[0] self.object.save() return HttpResponseRedirect(self.get_success_url()) 更新要保存的对象(WorkshopAttendee对象)(基于Workshop slug)字段,这是唯一的),然后保存更新的对象(Workshop)并将我踢到成功网址。

非常感谢@ init3的有用指针。非常感谢。