我在 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()
将产品传递给表单初始化函数并尝试:
self.fidels['product'].initial = product
感谢您的帮助
PS:一些关于SO的参考资料
这不起作用的主要原因是
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