首页 > 解决方案 > Django 自定义表单和 GenericView

问题描述

以下代码正在运行,但我想知道是否有更优雅的方法。我必须传递 specie_id,这样我才能将品种过滤到相应的品种。我可以将 specie_id 传递给视图,但我也有 Resident 模型(“specie”)中的信息。

get() 和 post() 都有几乎相同的代码,都传递了 specie_id。

风景

class ResidentUpdate(UpdateView):
    model = Resident
    template_name = "administration/resident_form.html"
    form_class = ResidentCreateForm

    def get(self, request, pk):
        initial = self.model.objects.get(id=pk)
        form = self.form_class(instance=initial, specie_id=initial.specie.id)
        return render(request, self.template_name, {"form": form})

    def post(self, request, pk):
        initial = self.model.objects.get(id=pk)
        form = self.form_class(request.POST, specie_id=initial.specie.id, instance=initial)
        if form.is_valid():
            form.save()
            return redirect("resident_detail", pk)
        return render(request, self.template_name, {"form", form})

表格

class ResidentCreateForm(ModelForm):

    class Meta:
        model = Resident
        fields = [
            "name",
            "specie",
            "breed",
            "gender",
            "gender_status",
            "birth_date",
            "organization",
            "social_behaviors",
            "notes",
        ]
        widgets = {
            "birth_date": DateInput(attrs={"class": "flatpickr"}),
            "specie": HiddenInput(),
        }

    def __init__(self, *args, **kwargs):
        self.specie_id = kwargs.pop("specie_id", None)
        super(ResidentCreateForm, self).__init__(*args, **kwargs)
        self.fields["specie"].initial = self.specie_id
        self.fields["breed"].queryset = Breed.objects.for_specie(self.specie_id)

编辑 :

@Alasdair 的回答很好,我想我更完善了一点。我的表单也用于创建视图。所以我添加了一个检查,看看我是否在 kwargs 中有 specie_id(创建),或者我是否必须使用实例中的 specie_id(更新)

def __init__(self, *args, **kwargs):
    self.specie_id = kwargs.pop("specie_id", None)
    super(ResidentForm, self).__init__(*args, **kwargs)
    if not self.specie_id:
        self.specie_id = self.instance.specie.id
    self.fields["specie"].initial = self.specie_id
    self.fields["breed"].queryset = Breed.objects.for_specie(self.specie_id)

标签: djangodjango-forms

解决方案


看起来你可以做到self.fields["breed"].queryset = Breed.objects.for_specie(self.initial.specie_id),那么你不需要传递specie_id给表单。

class ResidentCreateForm(ModelForm):

    class Meta:
        model = Resident
        fields = [
            "name",
            "specie",
            "breed",
            "gender",
            "gender_status",
            "birth_date",
            "organization",
            "social_behaviors",
            "notes",
        ]
        widgets = {
            "birth_date": DateInput(attrs={"class": "flatpickr"}),
        }

    def __init__(self, *args, **kwargs):
        super(ResidentCreateForm, self).__init__(*args, **kwargs)
        self.fields["breed"].queryset = Breed.objects.for_specie(self.instance.specie_id)

注意我已经删除了specie上面的隐藏输入,我认为没有必要。

UpdateView负责传递instance给表单,因此您可以简化视图。

from django.urls import reverse

class ResidentUpdate(UpdateView):
    model = Resident
    template_name = "administration/resident_form.html"
    form_class = ResidentCreateForm

    def get_success_url(self):
        """Redirect to resident_detail view after a successful update"""
        return reverse('resident_detail', args=[self.kwargs['pk']]

推荐阅读