2011-03-02 72 views
5

嗨 我有一个领域模型,用于Django应用程序,我想在一个表单上展示。我用自定义的ModelForms创建了我的应用程序(没有太多变化,某些字段被排除等)。该模型的依赖关系如下:django带自定义表单的内联表格

Complaint 
    \ 
    .--- CarInfo 
    .--- Customer 

我的观点功能是这样的:

def make(request): 
    if request.method == 'POST': 
    parameters = copy.copy(request.POST) 
    complaint = Complaint() 
    carInfo = CarInfo() 
    customer = Customer() 

    customer_form = CustomerForm(parameters, instance=customer) 
    carInfo_form = CarInfoForm(parameters, instance=carInfo) 
    parameters['complaint_date'] = get_current_date() 
    parameters['customer'] = 1 # dummy value to allow validation success 
    parameters['car_info'] = 1 # dummy value to allow validation success 
    form = ComplaintForm(parameters, instance=complaint) 
    if form.is_valid() and customer_form.is_valid() and carInfo_form.is_valid(): 
     carInfo_form.save() 
     customer_form.save() 
     parameters['customer'] = customer.id 
     parameters['car_info'] = carInfo.id 
     form = ComplaintForm(parameters, instance=complaint) 
     form.save() 
     return index(request) 
    else: 
    form = ComplaintForm() 
    carInfo_form = CarInfoForm() 
    customer_form = CustomerForm() 
    return render_to_response('complaints/make_complaint.html', {'complaint_form' : form, 'customer_form' : customer_form, 'carInfo' : carInfo_form}) 

我不喜欢这种方法太多了,而且它并不适用于所有环境下工作-thou我没有找到它不工作的原因。我一直在寻找修复这个代码,并发现像内联窗体集(http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#inline-formsets)。这个解决方案似乎没问题,但由于我的表单是自定义的,我可以使用它。

也许有人可以为我提供一些建议,如何妥善解决这种情况。清洁解决方案非常感谢。

编辑 有一种情况是我在这种解决方案不起作用。尽管在外键上设置了虚拟值,但当我调用is_valid()时,我得到FALSE,并显示错误消息说这些字段未设置。我正在用django 1.2.5观察这个问题 - 它发生在服务器上,我打算运行这个应用程序,但是我的笔记本电脑(也是django 1.2.5)没有这个问题。

+0

你可以发布你的模型类和表单吗? – DTing 2011-03-10 10:32:47

+0

答案更新了...... – FallenAngel 2011-03-10 12:10:01

回答

5

你可以改变你的投诉模型complaint_date到这样的事情

complaint_date = models.DateField(default=datetime.date.today())

这样你可以摆脱

parameters['complaint_date'] = get_current_date()

至于你多种形式的视图中,可以使用未绑定为你所需的行为形式。

通过在投诉表格中排除fk给汽车和客户,表格应该被验证。同时检查所有3种表单的.is_valid(),然后保存投诉对象所依赖的2个表单,使用提交到数据库(commit = False)创建投诉对象,添加客户的ID和汽车到那个物体,然后保存。

在您的视图中。

def make(request): 
    if request.method == 'POST': 
     customer_form = CustomerForm(request.POST) 
     carInfo_form = CarInfoForm(request.POST) 
     form = ComplaintForm(request.POST) 

     if form.is_valid() and customer_form.is_valid() and carInfo_form.is_valid(): 
      car_instance = carInfo_form.save() 
      customer_instance = customer_form.save() 

      complaint_instance = form.save(commit=False) 
      complaint_instance.car_info = car_instance 
      complaint_instance.customer_info = customer_instance   
      complaint_instance.save() 

      return index(request) 
    else: 
     form = ComplaintForm() 
     carInfo_form = CarInfoForm() 
     customer_form = CustomerForm() 

    context = { 'complaint_form' : form, 
       'customer_form' : customer_form, 
       'carInfo' : carInfo_form, 
       } 
    return render_to_response('complaints/make_complaint.html', context, context_instance=RequestContext(request)) 

编辑:

机型看起来就像这样:

class CarInfo(models.Model): 
    some_car_info = models.CharField() 

class Customer(models.Model): 
    some_customer_info = models.CharField() 

class Complaint(models.Model): 
    car_info = models.ForeignKey(CarInfo) 
    customer_info = models.ForeignKey(Customer) 
    some_complaint_info = models.CharField() 

forms.py应该是这样的:

class CarInfoForm(forms.ModelForm): 
    class Meta: 
     model = CarInfo 

class CustomerForm(forms.ModelForm): 
    class Meta: 
     model = Customer 

class ComplaintForm(forms.ModelForm): 
    class Meta: 
     model = Complaint 
     exclude = ('car_info', 'customer_info',) # or include = ('some_complaint_info',) 

让步行通过量小时图我写了上面: form in view docs

  • 在第一遍,不存在request.method所以我们创建3种unbound形式。

    else: 
        form = ComplaintForm() 
        carInfo_form = CarInfoForm() 
        customer_form = CustomerForm() 
    
  • 这些形式被传递给模板并呈现。

  • 当再次调用request.method ==“POST”来评估true时,我们使用来自request.POST的数据创建3个绑定的表单实例。

    if request.method == 'POST': 
        customer_form = CustomerForm(request.POST) 
        carInfo_form = CarInfoForm(request.POST) 
        form = ComplaintForm(request.POST) 
    
  • 接下来我们调用每个形式上.is_valid()方法。在我们的示例中,因为我们在我们的投诉模型表单中排除了'customer_info'和'car_info'外键字段,所以每个表单只检查是否验证了char输入字段。

  • 如果验证所有通过,那么我们就可以开始拯救我们的表格模型,这其中,我们需要小心填充我们的投诉的需要FK的:

    if form.is_valid() and customer_form.is_valid() and carInfo_form.is_valid(): 
         car_instance = carInfo_form.save() 
         customer_instance = customer_form.save() 
    
  • 有了这2种形式,我们可以调用。保存()照常。然而,我们会将返回值分配给car_instance和customer_instance。这些将包含我们刚在表单上使用.save()方法创建的CarInfo和Customer模型的实例。

  • 接下来,使用.save()方法中的commit=False参数,我们可以从绑定窗体(包含request.POST数据)创建一个对象,而不是将其保存到数据库。

     complaint_instance = form.save(commit=False) 
         complaint_instance.car_info = car_instance 
         complaint_instance.customer_info = customer_instance   
         complaint_instance.save() 
    
  • 为了使这个更清楚,你也可以创建一个新的投诉对象是这样的:

    complaint_info = form.cleaned_data.get('some_complaint_info') 
    complaint_instance = Complaint(car_info=car_instance, customer_info=customer_instance, some_complaint_info=some_complaint_info) 
    complaint_instance.save() 
    
  • 渲染

+0

这与我的解决方案没有太大差别。 ** form **应该如何验证carInfo和客户设置没有外键? – 2011-03-10 10:13:17

+0

@Marcin Cylke我相信.is_valid()正在检查表单中的字段是否有效。验证表单并验证模型是两件不同的事情。 http://docs.djangoproject.com/en/dev/ref/models/instances/#id1 – DTing 2011-03-10 10:28:00

+1

@Marcin,'ComplaintForm'应该验证正确,因为这些字段已经'exclude'd。试一试。 – DrMeers 2011-03-11 10:42:16

3

我想你已经拥有最干净和简单的方法,但如果你想要去尝试的formsets这些链接:

编辑。我想你可以通过虚拟值来解决问题(并修改request.POST,我可以继续猜测:),但@ kriegar显示了你如何避免这种情况。无论如何,在一个视图中保存几种形式并不难。 Django表单足以支持这种情况。我的观点是,明确地做到这一点是最干净和最简单的方式,formset不会改善情况。

+0

这些链接是非常有用的信息 – 2011-03-10 10:12:18

+0

既然你说这完全没问题,或许你知道奇怪行为的原因? - 我在这个问题上添加了一些注释(看EDITED的内容) – 2011-03-10 10:19:34

1

大概表单集工厂和在线表单集应解决您的问题...您可以修改或覆盖从模型创建的表单字段,对于子模型,您可以使用内联表单...

Formsets and inline formsets...

一个可能的解决方案:

在你的表单定义

class CarInfoFrm(forms.ModelForm): 
    class Meta: 
     model = CarInfo 
     fields = (....) 
carInfoForm = inlineformset_factory(Complaint, CarInfo, form=carInfoFrm,) 
CustomerForm = inlineformset_factory(Complaint, Customer, form=carInfoFrm,) 

在你看来:

complaint = Complaint() 
carInfo = CarInfo() 
customer = Customer() 

cus_form = CustomerForm(parameters, instance=complaint) 
car_form = CarInfoForm(parameters, instance=complaint) 
comp_form = ComplaintForm(parameters, instance=complaint) 

if cus_form.is_valid() and ...... : 
    comp = comp_form.save(commit=False)#do not save it yet 
    comp.<attr> = "some_value" #you can edit your data before save... 
    comp.save() 
    car = car_form(commit=False) 
    # do as complaint form... edit and save... 

编辑:我定义实例参数时做出misteke同时保存内联格式。所以我纠正它...

当您更新现有的记录,你会不会有问题,但最好是使用它像:

if comp_form.is_valid(): 
    comp = comp_form.save(commit=False) 
    comp.<attr> = "some_value" 
    comp.save() 
if car_form.is_valid(): 
    # edit if neccessary then save... 

if cust_form.is_Valid(): 
    # edit if neccessary then save... 

是什么让更容易,当你定义的形式,您是通过外键

carInfoForm = inlineformset_factory(Complaint, CarInfo, form=carInfoFrm,) 

设置父窗体而当你更新使用内嵌的形式,你与你的父母Compalaint记录初始化,

car_form = CarInfoForm(parameters, instance=complaint) 

因此,car_form不接受carInfo实例,而是一个投诉实例(这是我的第一个答案中的错误,所以我改正了它)。如果它创建了新的记录,它会自动将其绑定到相关的投诉记录。如果它是更新,它只会更新所需的字段。

对我来说,iti最好是使用框架的moehods而不是写你的拥有者。通过这样做,您将保证获得django所做的所有验证检查。

+0

这不是我写的更复杂的版本吗?你可以总结一下你的方法中的差异吗?我仍然担心,如果没有设置fk,**表单**将无法验证。将在今天晚些时候尝试。 – 2011-03-10 10:15:14

+0

阅读我对上面的表单和模型验证的评论,看起来还有另外一个问题。请张贴您的模型和表格。 – DTing 2011-03-10 19:52:13