正在使用Django Rest Framework(DRF)、django-filter和PostgreSQL,并且我们的一个端点出现了问题。
假设如下:
# models.py
class Company(models.Model):
name = models.CharField(max_length=50)
class Venue(models.Model):
company = models.ForeignKey(to="Company", on_delete=models.CASCADE)
name = models.CharField(max_length=50)
# create some data
company1 = Company.objects.create(name="Proper Ltd")
company2 = Company.objects.create(name="MyCompany Ltd")
Venue.objects.create(name="Venue #1", company=company1)
Venue.objects.create(name="Venue #2", company=company1)
Venue.objects.create(name="Property #1", company=company2)
Venue.objects.create(name="Property #2", company=company2)
# viewset
class CompanyViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = CompanyVenueSearchSerializer
queryset = (
Venue.objects.all()
.select_related("company")
.order_by("company__name")
)
permission_classes = (ReadOnly,)
http_method_names = ["get"]
filter_backends = (filters.DjangoFilterBackend,)
filterset_class = CompanyVenueListFilter
pagination_class = None
# filterset
class CompanyVenueListFilter(filters.FilterSet):
text = filters.CharFilter(method="name_search")
def name_search(self, qs, name, value):
return qs.filter(
Q(name__icontains=value)
| Q(company__name__icontains=value)
)
class Meta:
model = Venue
fields = [
"name",
"company__name",
]
# serializer
class CompanyVenueSearchSerializer(serializers.ModelSerializer):
company_id = serializers.IntegerField(source="company.pk")
company_name = serializers.CharField(source="company.name")
venue_id = serializers.IntegerField(source="pk")
venue_name = serializers.CharField(source="name")
class Meta:
model = Venue
fields = (
"company_id",
"company_name",
"venue_id",
"venue_name",
)
现在我们希望允许用户通过在请求中发送查询来过滤结果,例如curl -X GET https://example.com/api/company/?text=pr
。
序列化程序结果将类似于:
[
{
"company_id":1,
"company_name":"Proper Ltd",
"venue_id":1,
"venue_name":"Venue #1"
},
{ // update ORM to exclude this dict
"company_id":1,
"company_name":"Proper Ltd",
"venue_id":2,
"venue_name":"Venue #1"
},
{
"company_id":2,
"company_name":"MyCompany Ltd",
"venue_id":3,
"venue_name":"Property #1"
},
{
"company_id":2,
"company_name":"MyCompany Ltd",
"venue_id":4,
"venue_name":"Property #1"
}
]
预期结果:
希望重写ORM查询,以便如果筛选器("* pr *")匹配venue__name
,则返回所有地点。但如果筛选器匹配company__name
,则仅返回 * 一次 *,因此在上面的示例中,列表中的第二个dict将被排除/删除。
这可能吗?
2条答案
按热度按时间yqhsw0fo1#
您可以做的是过滤与
name
过滤匹配的Company
,并使用第一个相关的Venue
对其进行注解,然后将其结果与第二个要求组合,以使用name=value
返回venue访问
venue_qs
的值时执行的查询如下所示这是过滤器的外观
更新Django 3.2.16
上面的查询似乎不适用于此版本,因为它生成的查询在
V0."id"
周围的WHERE
子句中没有括号,查询块如下所示这会让PostgreSQL报错
对于
Django==3.2.16
,CompanyVenueListFilter
中的过滤方法可能如下所示:答案是基于其他stackoverflow答案和django文档
s71maibg2#
我们有一个临时的解决方案,我们对此有点担心,但它似乎起到了作用。我们不会把这个答案标记为被接受,因为我们仍然希望有人能有一个更像Python/ Django 的解决方案。