根据 url 预填充模型表单

问题描述 投票:0回答:1

我在 Django 表单上苦苦挣扎。我对框架的这一部分不太满意。 情况如下。我有一个包含 OneToOneField 的 ModelForm。我想使用 URL 中引用的对象预先填充 ModelChoice 字段。例如:catalog/location/add/7 向 pk=7 的产品添加位置 注意:如果不包含 PK,则只是未预先填写表格

models.py

class Product(models.Model):
   pass

class ProductLocation(geo_models.Model):
   product = geo_models.OneToOneField(Product, verbose_name=_('Product'), on_delete=geo_models.CASCADE, null=True,)
   geo_point = geo_models.PointField(verbose_name=_('Location'), blank=True)
   address = geo_models.CharField(verbose_name=_('Address'), max_length=255)

urls.py

urls += [
            re_path(r"^location/add/(?P<product_pk>\d+)/$",
                 self.add_update_location.as_view(),
                 name='catalogue-product-location-add'),  # Prepopulate product ModelChoiceField

            path("location/add",
                 self.add_update_location.as_view(),
                 name='catalogue-location-create'  # Empty product ModelChoiceField
                 ),

            path("location/<int:pk>",
                 self.add_update_location.as_view(),
                 name='catalogue-location-update')  # Edit an existing Location
        ]

views.py

class LocationCreateUpdateView(generic.UpdateView):
    form_class = ProductLocationForm

    creating = True
    product = None

    def get_object(self, queryset=None):
        """
        Extend the role of get_object to retrieve the product specified in the url
        """
        self.creating = "pk" not in self.kwargs
        if self.creating:
            if self.kwargs.get("product_pk"):
                self.product = get_object_or_404(Product, pk=self.kwargs["product_pk"])
            return None
        else:
            return super().get_object(queryset)

# Try this way
    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        if self.product and not self.request.POST.get('product'):
            kwargs["product"] = self.product
        return kwargs

# Or this way
    def get_initial(self):
        initial = super().get_initial()
        if self.product:
            initial["product"] = self.product
        return initial

forms.py


class ProductLocationForm(forms.ModelForm):
    def __init__(self, product=None, instance=None, *args, **kwargs):
        # I tried this
        if not instance and product:
            instance = ProductLocation(product=product)
        super().__init__(instance=instance, *args, **kwargs)

我尝试覆盖

get_initial()
将产品传递到表单但未验证,要求在列表中选择一个产品,而且它会删除初始值。

我还使用

get_form_kwargs()
将产品传递给表单初始化函数并尝试:

  • 将产品附加到 ProductLocation 实例
  • 在init中设置初始数据
  • 设置
    self.fidels['product'].initial = product

感谢您的帮助

PS:一些关于SO的参考资料

python django
1个回答
0
投票

这不起作用的主要原因是

UpdateView
确实会触发
.get_object(..)
,这会将
self.instance
设置为
.get_object(…)
的结果。根据您的用例,这并不总是需要的。如果
None
中没有
get_object()
,我们可以通过在
pk
中返回
self.kwargs
来使其可选:

from django.shortcuts import get_object_or_404


class LocationCreateUpdateView(generic.UpdateView):
    model = ProductLocation
    form_class = ProductLocationForm

    def get_object(self, queryset=None):
        creating = self.creating = 'pk' not in self.kwargs
        if not creating:
            return super().get_object(queryset)

    def get_initial(self):
        initial = super().get_initial()
        if 'product_pk' in self.kwargs:
            initial['product'] = get_object_or_404(
                Product, pk=self.kwargs['product_pk']
            )
        return initial
© www.soinside.com 2019 - 2024. All rights reserved.