问题
I am trying to use filters with a Wagtail Page model and a Orderable model. But I get duplicates in my filter now. How can I solve something like this?
My code:
class FieldPosition(Orderable):
page = ParentalKey('PlayerDetailPage', on_delete=models.CASCADE, related_name='field_position_relationship')
field_position = models.CharField(max_length=3, choices=FIELD_POSITION_CHOICES, null=True)
panels = [
FieldPanel('field_position')
]
def __str__(self):
return self.get_field_position_display()
class PlayerDetailPage(Page):
content_panels = Page.content_panels + [
InlinePanel('field_position_relationship', label="Field position", max_num=3),
]
class PlayerDetailPageFilter(FilterSet):
field_position_relationship = filters.ModelChoiceFilter(queryset=FieldPosition.objects.all())
class Meta:
model = PlayerDetailPage
fields = []
So what I am trying to do is create a filter which uses the entries from FIELD_POSITION_CHOICES
to filter out any page that has this position declared in the inline panel in Wagtail.
As you can see in the picture down below, the filters are coming through and the page is being rendered. (These are 2 pages with a list of 3 field positions).
So Page 1 and Page 2 both have a "Left Winger" entry, so this is double in the dropdown. The filtering works perfectly fine.
What can I do to prevent this?
The solution should be something like this (Credits to Harris for this):
I basically have one FieldPosition
object per page-field position, so it's listing all of the objects correctly. I suspect I should not use the model chooser there, but a list of the hard coded values in FIELD_POSITION_CHOICES
and then a filter to execute a query that looks something like PlayerDetailPage.objects.filter(field_position_relationship__field_position=str_field_position_choice)
. But what is the Django Filter way of doing this?
回答1:
Raf
In my limited simplistic view it looks like
class PlayerDetailPageFilter(FilterSet):
field_position_relationship = filters.ModelChoiceFilter(queryset=FieldPosition.objects.all())
is going to return all the objects from FieldPosition and if you have 2 entries for 'left wing' in here (one for page 1 and one for page 2) then it would make sense that this is duplicating in your list. So have you tried to filter this list queryset with a .distinct? Perhaps something like
class PlayerDetailPageFilter(FilterSet):
field_position_relationship = filters.ModelChoiceFilter(queryset=FieldPosition.objects.values('field_position').distinct())
回答2:
I found the solution after some trial and error:
The filter:
class PlayerDetailPageFilter(FilterSet):
field_position_relationship__field_position = filters.ChoiceFilter(choices=FIELD_POSITION_CHOICES)
class Meta:
model = PlayerDetailPage
fields = []
And then the view just like this:
context['filter_page'] = PlayerDetailPageFilter(request.GET, queryset=PlayerDetailPage.objects.all()
By accessing the field_position
through the related name of the ParentalKey field_position_relationship
with __
.
Then using the Django Filter ChoiceFilter
I get all the hard-coded entries now from the choice list and compare them against the entries inside the PlayerDetailPage
query set.
In the template I can get the list using the Django Filter method and then just looping through the query set:
<form action="" method="get">
{{ filter_page.form.as_p }}
<input type="submit" />
</form>
{% for obj in filter_page.qs %}
{{ obj }} >
{% endfor %}
来源:https://stackoverflow.com/questions/55832348/how-to-prevent-duplicates-when-using-modelchoicefilter-in-django-filter-and-wagt