Django ModelChoiceField:根据 url 中的 pk 过滤对象

Django ModelChoiceField: filtering object based on pk in url

我读过很多关于这个主题的问题,但是 none 的方法对我有用。

有3个相关模型:

class Trips(models.Model):
    lake = models.CharField("Lake", max_length=150)
    city = models.CharField("City", max_length=100, blank=True)
    s_date = models.DateTimeField("Starting Date", auto_now=False, auto_now_add=False)
    e_date = models.DateTimeField("Ending Date", auto_now=False, auto_now_add=False)
    trip_id = models.AutoField(primary_key=True)    

    class Meta:
        verbose_name = "Trip"
        verbose_name_plural = "Trips"

    def __str__(self):
        return f"{self.lake}-{self.trip_id}-{self.s_date}"

class Fisherman(models.Model):
    name = models.CharField("Fisherman", max_length=50)
    trip = models.ForeignKey(Trips, on_delete=models.CASCADE)
    fisherman_id = models.AutoField(primary_key=True)

    class Meta:
        verbose_name = "Fisherman"
        verbose_name_plural = "Fishermen"

    def __str__(self):
        return f"{self.name}-{self.fisherman_id}"


class Catch(models.Model):
    fish_type = models.CharField("Fish Type", max_length=50)
    catch_id = models.AutoField(primary_key=True)
    weight = models.DecimalField("Weight", max_digits=5, decimal_places=2)
    length = models.DecimalField("Length", max_digits=5, decimal_places=2, blank=True, null=True)
    datetime = models.DateTimeField("Catch Time", auto_now=False, auto_now_add=False)
    fisherman = models.ForeignKey(Fisherman, on_delete=models.CASCADE)
    trip = models.ForeignKey(Trips, on_delete=models.CASCADE)

    class Meta:
        verbose_name = "Catch"
        verbose_name_plural = "Catches"

    def __str__(self):
        return f"{self.fish_type}-{self.catch_id}"

我有一个 ModelForm 可以创建一个新的 catch。在这里,我使用 ModelChoiceField 来列出 Fishermen,但我不知道如何过滤它们。我只想显示属于该行的人

class CatchForm(forms.ModelForm):
    fisherman = forms.ModelChoiceField(queryset= Fisherman.objects.all())
    class Meta:
        model = Catch
        fields = ["fish_type", "weight", "length", "datetime", "fisherman"]
        widgets = {
            "datetime": forms.DateTimeInput(format='%Y-%m-%d %H:%M', attrs={'class':'datetimefield form-control'}),
        }

views.py

我读到应该在视图中使用 get_form_kwargs 来覆盖表单中的字段,但它对我不起作用。

class NewCatchView(CreateView):
    model = Catch
    form_class = CatchForm
    template_name = "new_trip/new_catch.html"
    
    # Probably, this is wrong
    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['fisherman'] = Fisherman.objects.filter(trip=self.kwargs.get('pk'))
        return kwargs
    
    def form_valid(self, form):
        form.instance.trip = Trips.objects.get(pk=self.kwargs['pk'])
        return super().form_valid(form)

    def get_success_url(self):
        return reverse('new_trip:trip_details', args=(self.kwargs['pk'],))

urls.py

path("trip_details/<int:pk>/new_catch/", views.NewCatchView.as_view(), name="new_catch"),

预先感谢您的帮助!

你快到了。您已经创建了 kwarg,所以现在您只需要在表单中使用它来覆盖原始查询集:

class CatchForm(forms.ModelForm):
    ...

    def __init__(self, *args, **kwargs):
        fisherman = kwargs.pop('fisherman')
        super().__init__(*args, **kwargs)
        self.fields['fisherman'].queryset = fisherman