【问题标题】:Setting model user to current user when using inlineformset_factory in Django在 Django 中使用 inlineformset_factory 时将模型用户设置为当前用户
【发布时间】:2017-05-08 12:20:39
【问题描述】:

我遇到了一个我花了几个小时试图克服的障碍,我希望得到一些指导。

我有两个模型:Listings 和 Addresses,结构如下:

class Listings(models.Model):
    created_date = models.DateTimeField(auto_now_add=True)
    pub_date = models.DateTimeField(auto_now_add=True)
    address = models.ForeignKey(Addresses)
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    is_active = models.BooleanField(default=1)

class Addresses(models.Model):
    address1 = models.CharField(max_length=100)
    address2 = models.CharField(max_length=100)
    address3 = models.CharField(max_length=100)
    address4 = models.CharField(max_length=100)
    postcode = models.CharField(max_length=8)

我也有这些:

class AddressForm(ModelForm):
    class Meta:
        model = Addresses
        fields = ['address1', 'address2', 'address3', 'address4', 'postcode']

class ListingForm(ModelForm):
    class Meta:
        model = Listings
        fields = ['user']

我正在尝试创建一个将添加新列表的表单,但是要输入的唯一信息是地址模型中的字段。提交表单后,我需要创建一个新的 Listings 对象和一个新的 Addresses 对象,但 Listings 对象的“用户”外键必须等于当前登录用户的 id。

这是视图:

@login_required(login_url='share:login_view',          redirect_field_name='share:addlisting')
def addlisting(request):

    ListingInlineFormSet = inlineformset_factory(Addresses, Listings, form=ListingForm, can_delete=False, extra=1)

    if request.method == 'POST':

        address_form = AddressForm(request.POST)
        if address_form.is_valid():
            new_address = address_form.save()
            listing_formset = ListingInlineFormSet(request.POST, request.FILES, instance=new_address)

            if listing_formset.is_valid():
                listing_formset.save()
                return HttpResponseRedirect(reverse('/listing_added/'))

    else:
        address_form = AddressForm()
        listing_formset = ListingInlineFormSet()

    return render(request, 'share/addlisting.html', {
        "address_form": address_form,
        "listing_formset": listing_formset,
    })

在其当前状态下,我得到一个包含所有地址字段的表单,以及一个下拉用户字段。提交表单后,它会创建一个包含两个外键的新列表:一个用于所选用户,另一个用于刚刚创建的新地址。这个最终结果是我想要的。但是,我不希望表单中有下拉用户字段 - 我需要将用户设置为当前用户。我尝试在 ListingForm 类中使用“exclude = ['user']”而不是“fields = ['user']”,但这会导致创建一个新地址而没有创建一个与之配套的列表。所以我得到的只是一个新地址,没有列表。

我做错了什么?我会很感激这个问题的解决方案,因为我已经把头撞在墙上很长一段时间了!

【问题讨论】:

  • 我应该提到包含ListingForm(而不仅仅是AddressForm)的原因是我计划在适当的时候在表单中包含其他字段(这将是Listings对象的一部分) - 我只是想首先获得表单结构。我有理由希望将地址与列表分开,因此不将地址放在列表对象中。

标签: django django-models django-forms inline-formset


【解决方案1】:

在这种情况下,我根本不会使用表单集。如果您需要收集用户信息来创建新列表,请使用单个ListingFormAddressForm,保存新地址,然后将ListingFormcommit=False 保存,将用户和地址分配给它,然后然后保存实例。

@login_required(login_url='share:login_view', redirect_field_name='share:addlisting')
def addlisting(request):
    if request.method == 'POST':
        address_form = AddressForm(request.POST, prefix="address")
        listing_form = ListingForm(request.POST, prefix="listing")
        if address_form.is_valid() and listing_form.is_valid():
            new_address = address_form.save()
            new_listing = listing_form.save(commit=False)
            new_listing.address = new_address
            new_listing.user = request.user
            new_listing.save()
            return HttpResponseRedirect(reverse('/listing_added/'))
    else:
        address_form = AddressForm(prefix="address")
        listing_form = ListingForm(prefix="listing")
    return render(request, 'share/addlisting.html', {
        "address_form": address_form,
        "listing_form": listing_form
    })

如果您在 Listings 上存在多对多关系,则需要在保存实例后显式保存这些关系,如下所述: https://docs.djangoproject.com/en/1.10/topics/forms/modelforms/#the-save-method

【讨论】:

  • 啊,我应该提到我计划在列表表单中添加更多字段,并且我有理由希望将地址保存在单独的表中......
  • 在这种情况下,您需要从列表表单中省略 user 字段,而仅指定您打算从用户那里收集的值。然后使用listing_form.save(commit=False)在内存中实例化新列表,设置其用户和地址属性(new_listing.address = new_address; new_listing.user = request.user),然后才保存新实例。无论地址是否在单独的表中,上述内容都不会改变。
  • 如果您尝试使用表单集,例如,向用户显示他们当前的列表并添加新列表,上述设计应该可以相当顺利地转换为表单集 - 我可能仍然会保留用户退出表单并在任何更改的实例上显式设置它,这比使用隐藏的输入小部件更受控制。
  • 我不确定我是否完全理解。我刚刚尝试在原始代码中的“if listing_formset.is_valid():”行下面执行以下操作:“new_listing = Listing_formset.save(commit=False) \ new_listing.address = new_address \ new_listing.user = request.user \ new_listing .save()”,但这不起作用,所以我想我误解了。我应该如何将其用于原始代码? (我假设我仍然需要 inlineformset_factory,因为我正在更改两个模型。)
  • 是的 - 表单集对于呈现可编辑的项目列表或一次创建新列表很有用,但如果您正在处理单个实例,则不是必需的。例如,您可以在购物车风格的应用程序中使用表单集,让用户有机会在结帐前查看和编辑购物车中的多个项目。或者再举一个例子,它们是 Django 管理员处理一对多关系的方式——在编辑关系的“一”侧时,可以使用表单集显示“多”实例。鉴于您计划只编辑一个实例,您可以避免使用它们。
猜你喜欢
  • 1970-01-01
  • 2021-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-01
  • 2011-07-22
相关资源
最近更新 更多