python - 如何将不同的模型添加到 ModelForm 作为额外字段?

标签 python django django-forms django-views

因此,我尝试在 __init__ 函数中向 ModelForm 类添加一个额外的字段,以便在创建/更新类 View 上我可以获取此模型并创建一个新模型。由于模型没有此字段,我如何将其添加到 __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 中我可以开始按给定的费率创建第三个模型

最佳答案

您可以使用 ModelChoiceField以便您可以在表单上选择费率

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() 方法中,您可以从 cleaned_data 检索 tariff 并创建相关的 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())

如果您需要过滤可用关税列表,您可能需要更改查询集。在您最初的问题中,我认为在表单的 __init__ 方法中使用 if instance 是没有意义的,因为实例不会传递给表单CreateView

关于python - 如何将不同的模型添加到 ModelForm 作为额外字段?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57408239/

相关文章:

python - Docker日志中的Python异常标记为流:stdout

python - 大写查菲尔德

Django 验证错误

django - 如何在 Django 管理区显示多对多关系字段(如果多对多关系使用 'through' )?

python - 根据列表或另一列中的值在 Pandas 数据框中动态选择列

python - Markup() 函数使用 Flask 返回标签之外的标记

python - 我应该如何为球队、球员和比赛对象设计 django 模型?

javascript - Django datetimefield 不显示新内联表单行的 datetimepicker 小部件

python - 关于 Flask session 的一些问题

python - 类型错误 : Field 'id' expected a number but got (()