Django:使用嵌套模型从许多关系查询中进行复杂排序和过滤
Posted
技术标签:
【中文标题】Django:使用嵌套模型从许多关系查询中进行复杂排序和过滤【英文标题】:Django: complex order by and filter by from many relations query with nested models 【发布时间】:2021-09-28 01:54:02 【问题描述】:我想要达到的目标: 我要列表
[
"location":"Loc 1",
"session":[
"start":"2021-01-01",
"counts":600,
"details":[
"id":13,
"length_max":21,
"length_min":15,
"length_avg":16,
"length_std":19,
"is_active":false,
"type":"dog"
]
]
,
"location":"Loc3",
"session":[
"start":"2021-01-01",
"counts":500,
"details":[
"id":15,
"length_max":19,
"length_min":16,
"length_avg":16,
"length_std":19,
"is_active":false,
"type":"dog"
]
]
]
我的视图集是
class SessionFilter(FilterSet):
type_filter = filters.CharFilter(method="filter_by_type")
def filter_by_type(self,queryset,name,value):
queryset = queryset.filter(session__details__type=value).distinct()
return queryset
class SessionModelViewSet(ModelViewSet):
queryset = Session.objects.all()
serializer_class = SessionSerializers
filter_backends = (DjangoFilterBackend,)
filter_class = SessionFilter
我正在尝试根据类型进行过滤,但无法获取我需要的内容。 我得到的结果是
[
"location":"Loc 1",
"session":[
"start":"2021-01-01",
"counts":600,
"details":[
"id":13,
"length_max":21,
"length_min":15,
"length_avg":16,
"length_std":19,
"is_active":false,
"type":"dog"
]
,
"start":"2021-01-01",
"counts":600,
"details":[
"id":7,
"length_max":39,
"length_min":25,
"length_avg":25,
"length_std":27,
"is_active":true,
"type":"cat"
,
"id":19,
"length_max":39,
"length_min":25,
"length_avg":25,
"length_std":27,
"is_active":false,
"type":"cat"
]
]
,
"location":"Loc3",
"session":[
"start":"2021-01-01",
"counts":500,
"details":[
"id":15,
"length_max":19,
"length_min":16,
"length_avg":16,
"length_std":19,
"is_active":false,
"type":"dog"
]
,
"start":"2021-01-01",
"counts":500,
"details":[
"id":9,
"length_max":39,
"length_min":25,
"length_avg":25,
"length_std":27,
"is_active":true,
"type":"cat"
,
"id":21,
"length_max":39,
"length_min":25,
"length_avg":25,
"length_std":27,
"is_active":false,
"type":"cat"
]
]
]
如何自定义过滤器或更改嵌套查询以获取所需的输出以及如何按 id 排序。直到第二个嵌套级别,我才能获取数据(也许并不复杂),但在第三级,我遇到了这个问题。
Model.py
class Place(models.Model):
id = models.IntegerField(primary_key=True)
location = models.CharField(max_length=100)
class Meta:
db_table = 'place'
managed=False
class Session(models.Model):
id = models.IntegerField(primary_key=True)
place = models.ForeignKey(Place,related_name='session',on_delete=models.CASCADE, null=True)
start = models.DateField(auto_now=True)
counts = models.IntegerField()
class Meta:
db_table = 'session'
managed=False
class Animal(models.Model):
id = models.IntegerField(primary_key=True)
sess = models.ForeignKey(Session,related_name='details',on_delete=models.CASCADE, null=True)
type = models.CharField(max_length=100)
is_active = models.BooleanField()
length_max = models.IntegerField()
length_min = models.IntegerField()
length_avg = models.IntegerField()
length_std = models.IntegerField()
class Meta:
db_table = 'animal'
managed=False
serializer.py
class AnimalSerializers(FlexFieldsModelSerializer):
class Meta:
model = Animal
fields = ["id","length_max","length_min","length_avg","length_std","is_active","type"]
class SessionSerializers(FlexFieldsModelSerializer):
class Meta:
model = Session
fields = ["start","counts","details"]
expandable_fields =
'details': (AnimalSerializers, 'many': True)
class PlaceSerializers(FlexFieldsModelSerializer):
class Meta:
model = Place
fields = ["location","session"]
expandable_fields =
'session': (SessionSerializers, 'many': True)
预取后我得到的 json 格式为
"location": "Loc 2",
"session": [
"start": "2021-01-01",
"counts": 300,
"details": [
"id": 14,
"length_max": 22,
"length_min": 16,
"length_avg": 16,
"length_std": 19,
"is_active": true,
"type": "dog"
]
,
"start": "2021-01-01",
"counts": 300,
"details": []
]
有没有办法消除并获取唯一需要的?
使用with过滤方法后,得到的json格式为
.prefetch_related(
Prefetch('session', queryset=Session.objects.filter(details__type=value)),
Prefetch('session__details', queryset=Details.objects.all().order_by('id'))),
)
[
"location": "Loc 3",
"session": [
"start": "2021-01-01",
"counts": 500,
"details": [
"id": 15,
"length_max": 19,
"length_min": 16,
"length_avg": 16,
"length_std": 19,
"is_active": false,
"type": "dog"
]
]
,
"location": "Loc 4",
"session": [
"start": "2021-01-02",
"counts": 800,
"details": [
"id": 1,
"length_max": 24,
"length_min": 18,
"length_avg": 25,
"length_std": 27,
"is_active": false,
"type": "cat"
,
"id": 4,
"length_max": 24,
"length_min": 18,
"length_avg": 25,
"length_std": 27,
"is_active": false,
"type": "cat"
,
"id": 16,
"length_max": 24,
"length_min": 18,
"length_avg": 16,
"length_std": 19,
"is_active": false,
"type": "dog"
]
,
"start": "2021-01-02",
"counts": 800,
"details": [
"id": 10,
"length_max": 29,
"length_min": 16,
"length_avg": 16,
"length_std": 19,
"is_active": false,
"type": "dog"
,
"id": 22,
"length_max": 29,
"length_min": 16,
"length_avg": 16,
"length_std": 19,
"is_active": false,
"type": "dog"
]
]
,
更新代码后的输出
[
"location": "Loc 1",
"session": [
"start": "2021-01-01",
"counts": 600,
"details": [
"id": 13,
"length_max": 21,
"length_min": 15,
"length_avg": 16,
"length_std": 19,
"is_active": false,
"type": "dog"
]
]
,
"location": "Loc 2",
"session": [
"start": "2021-01-01",
"counts": 300,
"details": [
"id": 14,
"length_max": 22,
"length_min": 16,
"length_avg": 16,
"length_std": 19,
"is_active": true,
"type": "dog"
]
]
,
"location": "Loc 3",
"session": [
"start": "2021-01-01",
"counts": 500,
"details": [
"id": 15,
"length_max": 19,
"length_min": 16,
"length_avg": 16,
"length_std": 19,
"is_active": false,
"type": "dog"
]
]
,
"location": "Loc 4",
"session": [
"start": "2021-01-02",
"counts": 800,
"details": [
"id": 16,
"length_max": 24,
"length_min": 18,
"length_avg": 16,
"length_std": 19,
"is_active": false,
"type": "dog"
]
,
"start": "2021-01-02",
"counts": 800,
"details": [
"id": 10,
"length_max": 29,
"length_min": 16,
"length_avg": 16,
"length_std": 19,
"is_active": false,
"type": "dog"
,
"id": 22,
"length_max": 29,
"length_min": 16,
"length_avg": 16,
"length_std": 19,
"is_active": false,
"type": "dog"
]
]
,
"location": "Loc 5",
"session": [
"start": "2021-01-02",
"counts": 400,
"details": [
"id": 17,
"length_max": 28,
"length_min": 19,
"length_avg": 16,
"length_std": 19,
"is_active": true,
"type": "dog"
]
,
"start": "2021-01-02",
"counts": 400,
"details": [
"id": 11,
"length_max": 38,
"length_min": 28,
"length_avg": 16,
"length_std": 19,
"is_active": false,
"type": "dog"
,
"id": 23,
"length_max": 38,
"length_min": 28,
"length_avg": 16,
"length_std": 19,
"is_active": true,
"type": "dog"
]
]
,
"location": "Loc 6",
"session": [
"start": "2021-01-02",
"counts": 450,
"details": [
"id": 18,
"length_max": 35,
"length_min": 26,
"length_avg": 16,
"length_std": 19,
"is_active": false,
"type": "dog"
]
,
"start": "2021-01-02",
"counts": 450,
"details": [
"id": 12,
"length_max": 15,
"length_min": 13,
"length_avg": 16,
"length_std": 19,
"is_active": true,
"type": "dog"
,
"id": 24,
"length_max": 15,
"length_min": 13,
"length_avg": 16,
"length_std": 19,
"is_active": false,
"type": "dog"
]
]
]
【问题讨论】:
你能分享你的序列化器和模型吗? 无论如何,您都可以尝试使用过滤后的查询集添加预取,如下所示:.prefetch_related(Prefetch('session__details', queryset=Details.objects.filter(type=value).order_by('id')))
@bdbd,感谢您的快速回复。它帮助了我。但是,现在数据与上一阶段一起显示,下一阶段数据为空。
@bdbd,如果订单是在较低的阶段 id 上制作的,订单会不会起作用?因为那部分没有用。请给我建议,如果有任何其他选择。
【参考方案1】:
试试这个:
.prefetch_related(
Prefetch('session', queryset=Session.objects.filter(details__type=value)),
Prefetch('session__details', queryset=Details.objects.filter(type=value).order_by('id'))),
)
这将删除所有不包含具有您正在查找的值的详细信息的会话,并将按其 ID 对这些会话中的所有详细信息进行排序。
【讨论】:
再次感谢,上面的数据对前 3 个数据集运行良好,从第 4 个数据集中,过滤和未过滤的数据都来了。排序也没有按预期工作。 我更新了我的答案以在session__details
中过滤Details
。可以再试一次吗?
您还想按会话还是按细节订购?
好像已经下单了。还是您希望它下降?
我只尝试按升序排列,前 4 个数字,即 13、14、15、16 个 id 是有序的,之后不是。过滤器按预期工作,而不是按顺序工作。以上是关于Django:使用嵌套模型从许多关系查询中进行复杂排序和过滤的主要内容,如果未能解决你的问题,请参考以下文章