I have Observer model which extends User model via OneToOneRelation. I made filtering for model Checklist which has foreign key to Observer. This is the models.py code:
class Observer(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
rating = models.IntegerField(default=0)
bird_ratings = models.ManyToManyField('BirdName', through='BirdRatings')
class Checklist(gismodels.Model):
date = models.DateField()
time_start = models.TimeField(null=True)
time_end = models.TimeField(null=True)
site_name = models.CharField(max_length=200)
municipality = models.CharField(max_length=200)
observer = models.ForeignKey(Observer, null=True, default='')
other_observers = models.CharField(max_length=150, default='')
note = models.CharField(max_length=2000)
location_note = models.CharField(max_length=2000, default='')
position = gismodels.PointField(null=True, srid=4326)
created = models.DateTimeField(db_index=True, null=True)
rating = models.IntegerField(default=0)
Then I made ChecklistFilter class in filters.py:
class ChecklistFilter(django_filters.FilterSet):
date = DateFromToRangeFilter(label='Datum pozorování', widget=RangeWidget(attrs={'display': 'inline'}))
#groups = django_filters.ModelMultipleChoiceFilter(queryset=User.objects.filter(), widget=forms.CheckboxSelectMultiple)
created = DateFilter(label='Datum vložení')
observer = ModelChoiceFilter(queryset=Observer.objects.filter(), label='Pozorovatel')
municipality = CharFilter(label='Obec')
oblast = CharFilter(label='Oblast')
rating = NumberFilter(label='Hodnocení')
class Meta:
model = Checklist
fields = ['date', 'created', 'observer', 'municipality', 'site_name', 'rating']
This is a part of my code from template, where I am using observer field:
<div class="col-sm-2">
{{ filter.form.observer.label_tag }}
{% render_field filter.form.observer class="form-control" %}
</div>
But the problem is that I dont't need get observer object but I need last_name from User model which is linked to Observer model. In forms I just extend ModelChoiceField and override label_from_instance() method. But this is not working here. Django-filter use this classes but overiding not working here. I tried this:
from .models import Checklist, Observer
from django.contrib.auth.models import User
import django_filters
from django_filters import DateFromToRangeFilter, DateFilter, CharFilter, NumberFilter, ModelChoiceFilter
from django_filters.widgets import RangeWidget
from django import forms
class ChecklistModelChoiceField(forms.ModelChoiceField):
def label_from_instance(self, obj):
return obj.user.last_name
class ChecklistFilter(django_filters.FilterSet):
date = DateFromToRangeFilter(label='Datum pozorování', widget=RangeWidget(attrs={'display': 'inline'}))
#groups = django_filters.ModelMultipleChoiceFilter(queryset=User.objects.filter(), widget=forms.CheckboxSelectMultiple)
created = DateFilter(label='Datum vložení')
observer = ChecklistModelChoiceField(queryset=Observer.objects.filter(), label='Pozorovatel')
municipality = CharFilter(label='Obec')
oblast = CharFilter(label='Oblast')
rating = NumberFilter(label='Hodnocení')
class Meta:
model = Checklist
fields = ['date', 'created', 'observer', 'municipality', 'site_name', 'rating']
The choice field then on the website has observer object:
EDIT
Yes, I tried both them. Then I tried:
class ChecklistModelChoiceField(django_filters.ModelChoiceFilter):
def label_from_instance(self, obj):
return obj.user.last_name
No error, but label_from_instance()
is not used. Still Observer object in select.
I have made a mistake. ModelChoiceFilter don't extend ChoiceField. The code in filters looks like this. It is just property:
class ModelChoiceFilter(QuerySetRequestMixin, Filter):
field_class = forms.ModelChoiceField
So my first idea won't work. Is there any other chance how to make what I need?
I found the solution. I use ChoiceFilter instead of ModelChoiceFilter and then for choices call a method where I create tuple of tuples with id of observer and the name from user model.
def get_last_names():
last_names = ()
observers = Observer.objects.all()
for obs in observers:
last_names += (obs.id, obs.user.last_name),
return last_names
observer = ChoiceFilter(choices=get_last_names, label='Observer')