wKa*_*vey 6 django django-filters multiplechoicefield modelmultiplechoicefield
我正在尝试构建一个MultipleChoiceFilter选项,其中的选择是相关模型(DatedResource)上可能存在的日期的集合。
到目前为止,这是我正在使用的东西...
resource_date = filters.MultipleChoiceFilter(
field_name='dated_resource__date',
choices=[
(d, d.strftime('%Y-%m-%d')) for d in
sorted(resource_models.DatedResource.objects.all().values_list('date', flat=True).distinct())
],
label="Resource Date"
)
Run Code Online (Sandbox Code Playgroud)
当它显示在html视图中时...
最初,这很好用,但是,如果我创建DatedResource具有新的不同date值的新对象,则需要重新启动我的Web服务器,以使它们成为此过滤器中的有效选择。我相信这是因为该choices列表是在Web服务器启动时进行一次评估的,而不是在每次我的页面加载时进行评估的。
有什么办法可以解决这个问题?也许通过一些创造性的使用ModelMultipleChoiceFilter?
谢谢!
编辑:
我尝试了一些简单的ModelMultipleChoice用法,但遇到了一些问题。
resource_date = filters.ModelMultipleChoiceFilter(
field_name='dated_resource__date',
queryset=resource_models.DatedResource.objects.all().values_list('date', flat=True).order_by('date').distinct(),
label="Resource Date"
)
Run Code Online (Sandbox Code Playgroud)
HTML表单显示得很好,但是选择不是过滤器可接受的值。我"2019-04-03" is not a valid value.假设收到验证错误,因为此过滤器需要datetime.date对象。我考虑过使用coerce参数,但是ModelMultipleChoice过滤器不接受这些参数。
根据狄克格罗滕的评论,我尝试使用链接问题中的建议。最终像
resource_date = filters.ModelMultipleChoiceFilter(
field_name='dated_resource__date',
to_field_name='date',
queryset=resource_models.DatedResource.objects.all(),
label="Resource Date"
)
Run Code Online (Sandbox Code Playgroud)
这也不是我想要的,因为HTML现在的形式是:a)显示str每个的表示形式DatedResource,而不是DatedResource.date字段; b)它们不是唯一的(例如,如果我有两个DatedResource对象相同date,则它们的两种str表示形式都出现在这也是不可持续的,因为我有200k + DatedResources,并且尝试全部加载时页面都挂起(与values_list过滤器相比,该过滤器可以在几秒钟内提取所有不同的日期。
一种简单的解决方案是重写__init__()filterset类的方法。
from django_filters import filters, filterset
class FooFilter(filterset.FilterSet):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
try:
self.filters['user'].extra['choices'] = [(d, d.strftime('%Y-%m-%d')) for d in sorted(
resource_models.DatedResource.objects.all().values_list('date', flat=True).distinct())]
except (KeyError, AttributeError):
pass
resource_date = filters.MultipleChoiceFilter(field_name='dated_resource__date', choices=[], label="Resource Date")Run Code Online (Sandbox Code Playgroud)
注意:choices=[]在您的字段中提供filterset类的定义
我使用以下依赖项测试并验证了此解决方案
。1. Python 3.6
2. Django 2.1
3. DRF 3.8.2
4. django-filter 2.0.0
我使用以下代码重现此行为。
# models.py
from django.db import models
class Musician(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return f'{self.name}'
class Album(models.Model):
artist = models.ForeignKey(Musician, on_delete=models.CASCADE)
name = models.CharField(max_length=100)
release_date = models.DateField()
def __str__(self):
return f'{self.name} : {self.artist}'
# serializers.py
from rest_framework import serializers
class AlbumSerializer(serializers.ModelSerializer):
artist = serializers.StringRelatedField()
class Meta:
fields = '__all__'
model = Album
# filters.py
from django_filters import rest_framework as filters
class AlbumFilter(filters.FilterSet):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.filters['release_date'].extra['choices'] = self.get_album_filter_choices()
def get_album_filter_choices(self):
release_date_list = Album.objects.values_list('release_date', flat=True).distinct()
return [(date, date) for date in release_date_list]
release_date = filters.MultipleChoiceFilter(choices=[])
class Meta:
model = Album
fields = ('release_date',)
# views.py
from rest_framework.viewsets import ModelViewSet
from django_filters import rest_framework as filters
class AlbumViewset(ModelViewSet):
serializer_class = AlbumSerializer
queryset = Album.objects.all()
filter_backends = (filters.DjangoFilterBackend,)
filter_class = AlbumFilter
Run Code Online (Sandbox Code Playgroud)
在这里,我使用了django-filterwith DRF。
现在,我通过Django管理控制台填充了一些数据。之后,专辑api如下所示,

而我得到了release_date作为

然后,我通过Django admin添加了一个新条目-(截图),然后刷新了DRF API端点,可能的选择如下所示,

| 归档时间: |
|
| 查看次数: |
263 次 |
| 最近记录: |