0

我在工作Django 1.11

我有三个模型,businessbusiness_addressbusiness_phonewherebusiness_address和 与business_phon相关联business

每当添加新业务时,business_address我都想创建字段。business_phonebusiness

为此,我实施了`

模型.py

class Business(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    name = models.CharField(max_length=200)
    business_type = models.ForeignKey(BusinessType, on_delete=models.CASCADE)

    class Meta:
        db_table = 'businesses'

    def __str__(self):
        return self.name


class BusinessAddress(models.Model):
    business = models.OneToOneField(Business, on_delete=models.CASCADE)
    line_1 = models.CharField(max_length=200)
    line_2 = models.CharField(max_length=200)

    class Meta:
        db_table = 'business_addresses'

    def __str__(self):
        return '%s, %s, %s, %s' % (self.line_1, self.line_2, self.city, self.state)


class BusinessPhone(models.Model):
    business = models.ForeignKey(Business, on_delete=models.CASCADE)
    phone_number = models.CharField(max_length=15, default=None)

    class Meta:
        db_table = 'business_phones'

    def __str__(self):
        return self.phone_number

表格.py

class BusinessForm(ModelForm):
    class Meta:
        model = Business
        exclude = ()

class BusinessAddressForm(ModelForm):
    class Meta:
        model = BusinessAddress
        fields = '__all__'

class BusinessPhoneForm(ModelForm):
    class Meta:
        model = BusinessPhone
        exclude = ()

BusinessAddressFormSet = inlineformset_factory(
    Business,
    BusinessAddress,
    form=BusinessAddressForm,
    extra=1,
    can_delete=False
)

BusinessPhoneFormSet = inlineformset_factory(
    Business,
    BusinessPhone,
    form=BusinessPhoneForm,
    extra=1,
    can_delete=False
)

视图.py

class BusinessCreate(CreateView):
    model = Business
    fields = ['name', 'business_type']

    def get_context_data(self, **kwargs):
        data = super(BusinessCreate,self).get_context_data(**kwargs)

        if self.request.POST:
            data['business_address'] = BusinessAddressFormSet(self.request.POST)
            data['business_phone'] = BusinessPhoneFormSet(self.request.POST)
        else:
            data['business_address'] = BusinessAddressFormSet()
            data['business_phone'] = BusinessPhoneFormSet()
        return data

    def form_valid(self, form):
        context = self.get_context_data()
        form.instance.user = self.request.user
        business_address = context['business_address']
        business_phone = context['business_phone']
        with transaction.atomic():
            self.object = form.save()

            if business_address.is_valid():
                business_address.instance = self.object
                business_address.save()
            if business_phone.is_valid():
                business_phone.instance = self.object
                business_phone.save()

        return super(BusinessCreate, self).form_valid(form)

    def get_success_url(self):
        messages.success(self.request, 'Business Added Successfully')
        return reverse('business:list')

并在template.html

<form action="POST">
  {% csrf_token %}
  {% form.as_p %}

  // address
  {{ business_address.management_form }}
  // business fields
  {% render_field business_address.form.line_1 %}
  {% render_field business_address.form.line_2 %}


  // phone field
  {{ business_phone.management_form }}
  {% render_field business_phone.form.phone_number %}
</form>

但是当我填写所有详细信息时,只有business is saving in database and there is no record created for电话and地址`型号的详细信息,甚至没有错误。

4

2 回答 2

1

你说有一个错误,但你没有在你的问题中显示它。错误(以及整个回溯)比您编写的任何内容都更重要(可能来自 forms.py 和 views.py)

由于表单集和在同一个表单上使用多个表单,您的案例有点棘手CreateView。互联网上没有很多(或没有很多好的)例子。直到你在 django 代码中挖掘内联表单集是如何工作的,你才会遇到麻烦。

好的,直奔主题。您的问题是表单集未使用与主表单相同的实例进行初始化。当您的 amin 表单将数据保存到数据库时,formset 中的实例不会更改,最后您没有主对象的 ID 以便将其作为外键。在 init 之后更改instance表单属性的属性不是一个好主意。

  • 在正常形式中,如果你在你之后改变它,is_valid你会得到不可预知的结果。
  • 对于表单集,即使在 init 之后直接更改instance属性也无济于事,因为表单集中的表单已经用某个实例进行了初始化,之后更改它也无济于事。

好消息是你可以instance在 Formset 初始化之后改变属性,因为在 Formset 初始化之后所有的表单instance属性都会指向同一个对象。

你有两个选择:

  1. 如果是表单集,而不是设置instance属性,只设置instance.pk. (这只是我从未做过的猜测,但我认为它应该可以工作。问题是它看起来像黑客)。
  2. 创建一个将同时初始化所有表单/表单集的表单。当它的is_valid()方法被调用时,所有的形式都应该被验证。调用它的save()方法时,必须保存所有表单。然后您需要将form_class您的属性设置CreateView为该表单类。唯一棘手的部分是,在初始化主表单后,您需要使用instance第一个表单的初始化其他(formsests)。您还需要将表单/表单集设置为表单的属性,以便在模板中访问它们。

当我需要创建一个包含所有相关对象的对象时,我使用第二种方法。这会将业务逻辑与视图逻辑分开,因为从视图的角度来看,您只有一个表单,它可以是:

  • 用一些数据初始化(在这种情况下是 POST 数据)
  • 检查有效性is_valid()
  • 有效时可以保存save()

您保留了表单界面,如果您正确制作了表单,您甚至可以使用它来创建对象以及更新对象及其相关对象,并且视图将非常简单。

于 2017-10-08T07:15:04.023 回答
0

我猜这会business_address.is_valid()返回 False,可能是因为业务没有传递给表单并且它抱怨它是一个必填字段。

于 2017-10-05T09:58:55.030 回答