【问题标题】:Custom label for instance with django-filter自定义标签,例如使用 django-filter
【发布时间】:2017-03-24 19:56:28
【问题描述】:

我有通过 OneToOneRelation 扩展用户模型的观察者模型。我对具有 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)

然后我在 filters.py 中创建了 ChecklistFilter 类:

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-filter 使用这些类,但覆盖在这里不起作用。我试过这个:

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

然后网站上的选择字段有观察者对象:

编辑
是的,我都试过了。然后我尝试了:

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

没有错误,但没有使用label_from_instance()。仍在选择中的观察者对象。

我犯了一个错误。 ModelChoiceFilter 不扩展 ChoiceField。过滤器中的代码如下所示。它只是财产:

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

所以我的第一个想法行不通。还有其他机会制作我需要的东西吗?

【问题讨论】:

  • 我不确定您的代码是如何工作的。一个问题是ChecklistFilter.observer 是一个表单域而不是一个过滤器。
  • 我搞错了。 ModelChoiceFilter 不扩展 ModelChoiceField。它只是财产。所以我只是覆盖了这个类中不存在的方法,并且该方法从未使用过。

标签: django django-models django-forms django-filter modelchoicefield


【解决方案1】:

我知道这个问题已经存在一年多了,但我遇到了同样的问题并使用 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

【讨论】:

  • 这实际上是比公认的答案更具可扩展性和更简洁的解决方案。对于那些需要更复杂的标签检索的人,应该只在模型类上添加一个方法并在 lambda 中调用它
【解决方案2】:

我找到了解决方案。我使用 ChoiceFilter 而不是 ModelChoiceFilter,然后为选择调用一个方法,在该方法中我创建具有观察者 ID 和用户模型名称的元组的元组。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-07-07
    • 1970-01-01
    • 1970-01-01
    • 2010-10-10
    • 2011-07-11
    • 1970-01-01
    • 2011-09-21
    • 1970-01-01
    相关资源
    最近更新 更多