因此,我试图在__init__
函数的ModelForm类中添加一个额外的字段,以便在Create / Update类视图中可以获取此模型并创建一个新模型。由于“模型”没有此字段,我如何将其添加到__init__
函数中?还是可以通过其他方法添加此字段?
我尝试重写__init__
方法以将该字段包括在ModelForm类中,但这仍然引发错误,认为参数是意外的
class MeterInstallationForm(ModelForm):
class Meta:
model = MeterInstallation
fields = METER_INSTALLATION_DEFAULT_FIELDS
def __init__(self, *args, **kwargs):
instance = kwargs.get("instance")
super(MeterInstallationForm, self).__init__(*args, **kwargs)
if instance:
# get tariff info in the form
# self.fields["tariff"] = instance.tariff
self.fields["tariff"] = TariffApplication.objects.filter(meter_installation__pk=instance.meter_installation.pk).values_list("tariff", flat=True)
class MeterInstallationCreateView(MeterInstallationsViewMixin, LoginRequiredMixin, CreateView):
template_name = "meter_installations/meter_installation_create.html"
fields = (
"name",
"meter_type",
"parent",
"meter",
"building",
"initial_reading",
"final_reading",
"active_after",
"active_until",
"comment",
)
form_class = MeterInstallationForm
meter_installation_create_view = MeterInstallationCreateView.as_view()
class MeterInstallation(ActiveAfterUntilModel, DateTrackedModel, MPTTModel, NamedModel): # type: ignore
meter_type = models.ForeignKey(
MeterType,
on_delete=models.PROTECT,
null=False,
blank=False,
related_name="installations",
verbose_name=_("Meter Installation type"),
)
parent = TreeForeignKey(
"self", on_delete=models.CASCADE, null=True, blank=True, related_name="children", db_index=True
)
meter = models.ForeignKey(
Meter, on_delete=models.PROTECT, related_name="installations", null=False, blank=False, verbose_name=_("Meter")
)
building = models.ForeignKey(
Building,
on_delete=models.PROTECT,
related_name="meter_installations",
null=True,
blank=False,
verbose_name=_("Building"),
)
places = models.ManyToManyField(Place, related_name="meter_installations", blank=False, verbose_name=_("Places"))
initial_reading = models.DecimalField(
decimal_places=4, max_digits=10, null=False, blank=False, default=0, verbose_name=_("Initial reading")
)
final_reading = models.DecimalField(
decimal_places=4, max_digits=10, null=True, blank=True, default=0, verbose_name=_("Final reading")
)
class MPTTMeta:
order_insertion_by = ["meter"]
def get_absolute_url(self):
return reverse("meter-installations:meter-installation-detail", kwargs={"pk": self.pk})
def delete(self, *args, **kwargs):
first_lvl_children = self.get_children().filter(level=1)
for first_lvl_child in first_lvl_children:
first_lvl_child.parent = None
first_lvl_child.save()
for leaf in first_lvl_child.get_children():
leaf.parent = first_lvl_child
leaf.save()
tree_id = first_lvl_child.tree_id
MeterInstallation.objects.partial_rebuild(tree_id)
super(MeterInstallation, self).delete(*args, **kwargs)
def __str__(self):
return f"[{self.pk}] type: {self.meter_type_id}, meter: {self.meter_id}"
class Tariff(ActiveAfterUntilModel, NamedModel, DateTrackedModel):
tariff_type = models.ForeignKey(
MeterType,
on_delete=models.PROTECT,
null=False,
blank=False,
related_name="tariffs",
verbose_name=_("Tariff type"),
)
building = models.ForeignKey(
Building, on_delete=models.PROTECT, related_name="tariffs", null=True, blank=False, verbose_name=_("Building")
)
unit_name = models.CharField(max_length=100, null=False, blank=True, unique=False, verbose_name=_("Unit name"))
unit_price = models.DecimalField(
decimal_places=4, max_digits=10, null=False, blank=False, default=0.0, verbose_name=_("Unit price")
)
VAT = models.DecimalField(decimal_places=2, max_digits=10, null=True, blank=True, verbose_name=_("VAT"))
class Meta:
unique_together = ("name", "tariff_type", "active_after", "active_until")
def get_absolute_url(self):
return reverse("tariffs:tariff-detail", kwargs={"pk": self.pk})
def __str__(self) -> str:
return (
f"[{self.pk}] "
f"type: {self.tariff_type_id}, "
f"building: {self.building_id}, "
f"price: {self.unit_price}, "
f"VAT: {self.VAT}, "
f"active_until: {self.active_until}"
)
class TariffApplication(ActiveAfterUntilModel, DateTrackedModel): # type: ignore
tariff = models.ForeignKey(
Tariff,
on_delete=models.PROTECT,
null=False,
blank=False,
related_name="tariff_applications",
verbose_name=_("Tariff Applications"),
)
meter_installation = models.ForeignKey(
"MeterInstallation",
on_delete=models.PROTECT,
null=False,
blank=False,
related_name="tariff_applications",
verbose_name=_("Meter Installation"),
)
def __str__(self) -> str:
return f"[{self.pk}] tariff: {self.tariff_id}, meter installation: {self.meter_installation_id}"
我很想知道如何进行这项工作,以便在CreateView中可以根据给定的价目表开始创建第三个模型
答案 0 :(得分:1)
您可以在ModelForm中包括额外的字段,并在您的视图中进行设置,例如:
# forms.py
class MeterInstallationForm(ModelForm):
class Meta:
model = MeterInstallation
fields = METER_INSTALLATION_DEFAULT_FIELDS + ('tariff',)
# views.py
class MeterInstallationCreateView(MeterInstallationsViewMixin, LoginRequiredMixin, CreateView):
template_name = "meter_installations/meter_installation_create.html"
fields = (
"name",
"meter_type",
"parent",
"meter",
"building",
"initial_reading",
"final_reading",
"active_after",
"active_until",
"comment",
)
form_class = MeterInstallationForm
def form_valid(self, form):
form.instance.tariff = forms.TariffApplication(form.data)
return super().form_valid(form)
答案 1 :(得分:1)
您可以使用ModelChoiceField
,以便可以在表单上选择tariff
。
class MeterInstallationForm(ModelForm):
class Meta:
model = MeterInstallation
fields = METER_INSTALLATION_DEFAULT_FIELDS
def __init__(self, *args, **kwargs):
super(MeterInstallationForm, self).__init__(*args, **kwargs)
self.fields["tariff"] = forms.ModelChoiceField(queryset=Tariff.objects.all())
然后在您的form_valid()
方法中,您可以从tariff
中检索cleaned_data
并创建相关的TariffApplication
。
def form_valid(self, form):
instance = form.save()
TariffApplication.objects.create(tariff=form.cleaned_data['tariff'], meter_installation=instance)
return HttpResponseRedirect(self.get_success_url())
如果需要过滤可用关税列表,则可能需要更改查询集。在您最初提出的问题中,我认为在表单的if instance
方法中使用__init__
是没有道理的,因为不会为CreateView
将实例传递到表单。 / p>