Пользовательская метка, например, с django-filter

У меня есть модель Observer, которая расширяет модель пользователя через OneToOneRelation. Я сделал фильтрацию для модели Checklist, у которой есть внешний ключ для Observer. Это код models.py:

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)

Затем я сделал класс ChecklistFilter в filter.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']

Это часть моего кода из шаблона, где я использую поле наблюдателя:

<div class="col-sm-2">
    {{ filter.form.observer.label_tag }}
    {% render_field filter.form.observer class="form-control" %}
</div>

Но проблема в том, что мне не нужно получать объект наблюдателя, а мне нужно last_name из модели пользователя, которая связана с моделью наблюдателя. В формах я просто расширяю ModelChoiceField и переопределяю метод label_from_instance(). Но это здесь не работает. Django-фильтр использует эти классы, но переопределение здесь не работает. Я пробовал это:

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']

Затем поле выбора на веб-сайте имеет объект-наблюдатель: введите здесь описание изображения

EDIT
Да, я пробовал оба варианта. Затем я попробовал:

class ChecklistModelChoiceField(django_filters.ModelChoiceFilter):
    def label_from_instance(self, obj):
        return obj.user.last_name

Нет ошибки, но label_from_instance() не используется. Все еще объект Observer в select.

Я сделал ошибку. ModelChoiceFilter не расширяет ChoiceField. Код в фильтрах выглядит так. Это просто собственность:

class ModelChoiceFilter(QuerySetRequestMixin, Filter):
    field_class = forms.ModelChoiceField

Так что моя первая идея не сработает. Есть ли другой шанс, как сделать то, что мне нужно?


person Bulva    schedule 24.03.2017    source источник
comment
Я не уверен, как работает ваш код. Одна проблема заключается в том, что ChecklistFilter.observer — это поле формы, а не фильтр.   -  person Sherpa    schedule 26.03.2017
comment
Я сделал ошибку. ModelChoiceFilter не расширяет ModelChoiceField. Это только собственность. Поэтому я просто переопределяю метод, которого нет в этом классе, и этот метод никогда не использовался.   -  person Bulva    schedule 26.03.2017


Ответы (2)


Я знаю, что этому вопросу больше года, но я столкнулся с той же проблемой и нашел решение с помощью ModelChoiceFilter. Итак, если кто-то еще столкнулся с этим:

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 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']

    def __init__(self, *args, **kwargs):
        super(ChecklistFilter, self).__init__(*args, **kwargs)
        # You need to override the label_from_instance method in the filter's form field
        self.filters['thon_group'].field.label_from_instance = lambda obj: obj.user.last_name
person DHerls    schedule 16.07.2018

Я нашел решение. Я использую ChoiceFilter вместо ModelChoiceFilter, а затем для выбора вызываю метод, в котором я создаю кортеж кортежей с идентификатором наблюдателя и именем из пользовательской модели.

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')
person Bulva    schedule 26.03.2017