为内联FormSet同时调用多个实例

时间:2013-08-05 23:42:15

标签: django inline-formset

我在显示带有多个实例对象的内联formset时遇到问题。我想要一个所有Owner的列表以及所有Pet的内联formset,所有这一页都是一页。

下面的代码可以工作,但一次只能调用1个所有者对象。有什么建议吗?

这是一个来自Django DatabaseError "more than one row returned by a subquery used as an expression" Editable related fields to object

的新问题

models.py

class Teacher(models.Model):
    teacher = models.CharField(max_length=300)

class Owner(models.Model):
   relevantteacher = models.ForeignKey(Teacher)     
   owner = models.CharField(max_length=300)

class PetName(models.Model):
    relevantowner = models.ForeignKey(Owner)
    pet_name = models.CharField(max_length=50)

forms.py

class OwnerForm(forms.ModelForm):
    class Meta:
       model = Owner

PetNameFormSet = inlineformset_factory(Owner,
    PetName,
    can_delete=False,
    extra=3,
    form=OwnerForm)

views.py

def petname(request, teacher_id):
   teacher = get_object_or_404(Teacher, pk=teacher_id)

   owners = Owner.objects.filter(relevantteacher=teacher_id)
   owner = owners[0]

   if request.method == "POST":
      petNameInlineFormSet = PetNameFormSet(request.POST, request.FILES, instance=owner)

      if petNameInlineFormSet.is_valid():
         petNameInlineFormSet.save()

         return HttpResponseRedirect(reverse('success'))

   else:
      petNameInlineFormSet = PetNameFormSet(instance=owner) 

   context = {'teacher': teacher, 'owner': owner, 'petNameInlineFormSet' : petNameInlineFormSet}
   return render(request, 'petname.html', context)

HTML petname.html

   {% load url from future %}
 <form class="petname_form" action="{% url "petname" teacher.id %}" method="post">{% csrf_token %}
   {{ teacher }}
   {{ owner.as_table }}
   {{ petNameInlineFormSet.as_table }}
 </form>

更新

HTML

{% for owner_form in owner_forms %}
    <form class="petname_form" action="{% url "petname" teacher.id %}" method="post">{% csrf_token %
     {% for o in owners %}
      {{o.owner}} has pets:<br/> //owner is the PK of the Owner model
         {{ owner_forms.relevantteacher }}
         {{ owner_forms.as_table }}
         {{ owner_forms.inline_form.as_table }}
     {% endfor %}
    </form>

1 个答案:

答案 0 :(得分:1)

基本上,您需要做的是编译要呈现的所有者表单列表。验证后,您必须保留每个表单的错误和成功消息,并呈现结果。

这是一个基于views.py实现上述内容的半伪代码示例:

owner_forms = []

if request.method == "POST":
    for owner in owners:
        #passing instance here may yeild unexpected behavior; django is aware of instance based on request.POST data.
        owner_form = PetNameFormSet(request.POST, request.FILES) 
        owner_forms.append(owner_form)

        if petNameInlineFormSet.is_valid():
            petNameInlineFormSet.save()

else:
    for owner in owners:
        owner_form = PetNameFormSet(instance=owner)
        owner_forms.append(owner_form)

context['owner_forms'] = owner_forms

现在,在owner_forms中呈现每个表单:

{% for owner_form in owner_forms %}
    <form class="petname_form" action="{% url "petname" teacher.id %}" method="post">{% csrf_token %}
       {% refer to the teacher object associated with the object the form is generated on %}
       {{ owner_form.relevantteacher }}
       {{ owner_form.as_table }}
       {{ owner_form.inline_form.as_table }}
    </form>
{% endfor %}

其他建议:

    根据使用的数据库,
  1. max_length=300存在问题。一般的经验法则是将CharField限制为255个字符。大于255的任何内容都应该是TextField。
  2. Django允许懒惰地引用ForeignKeys,用models.ForeignKey(Model)替换models.ForeignKey("Model")的实例,以防止将来出现潜在的竞争条件。