[英]Django - Multi filtering queryset return empty queryset
I have a problem with queryset in Django 2.0, after some research, I don't find any problem looks like mine. 我在Django 2.0中的queryset有问题,经过一些研究,我发现没有任何问题像我的一样。
I think it's because of my very old legacy database create by someone I didn't know. 我认为这是因为我不认识的人创建了非常旧的旧数据库。
So, I have a sqlite database who looks like this: 因此,我有一个如下所示的sqlite数据库:
Has you can see, the Table Properties don't have primary_key
, so i made a models
with django inspectdb
command who looks like this: 您是否看到,表属性没有
primary_key
,所以我使用django inspectdb
命令制作了一个models
,该models
如下所示:
from django.db import models
class Record(models.Model):
id = models.IntegerField(db_column='ID', primary_key=True)
class Meta:
db_table = 'Records'
def __str__(self):
return "%s" % self.id
class Propertie(models.Model):
id = models.ForeignKey(Record, models.DO_NOTHING, db_column='ID', primary_key=True)
item = models.CharField(db_column='Item', max_length=500)
value = models.CharField(db_column='Value', max_length=500)
class Meta:
db_table = 'Properties'
def __str__(self):
return '[%s]- %s -> %s' % (self.item, self.value, self.id)
I set Properties.id
as primary_key
but it's a ForeignKey
and Django say to set this field as OneToOneField
and it's normal and logic, but 1 Record
is linked to 9 Properties
so Porpertie.id
can't be unique
this is my first problem because I can't alter the database. 我将
Properties.id
设置为primary_key
但是这是一个ForeignKey
并且Django说要将此字段设置为OneToOneField
,这是正常现象和逻辑,但是1 Record
链接到9个Properties
因此Porpertie.id
不能unique
这是我的第一个问题,因为我无法更改数据库。
My second and real problem is when I run this query:
我的第二个也是真正的问题是当我运行此查询时:
def my_view(request):
epoch = datetime.date(1970, 1, 1)
period_from = stat_form.cleaned_data.get("period_from")
period_to = stat_form.cleaned_data.get("period_to")
product = stat_form.cleaned_data.get("kit")
timestamp_from = period_from - epoch
timestamp_to = period_to - epoch
records = Record.objects.using("statool").filter(
propertie__item="product",
propertie__value=product,
).filter(
propertie__item="stamp",
propertie__value__gt=str(int(timestamp_from.total_seconds())),
propertie__value__lt=str(int(timestamp_to.total_seconds())),
).count()
this QuerySet
is empty but it should return approximately 16XXX Record
I don't know what happens? 此
QuerySet
为空,但应返回大约16XXX Record
我不知道会发生什么?
Because if I do this query: 因为如果执行此查询:
records = Record.objects.using("statool").filter(
propertie__item="product",
propertie__value=product,
)
It returns a result but the second filter doesn't work ... 它返回结果,但是第二个过滤器不起作用...
The goal of those request is to get the Record
out with the specific date and product name. 这些要求的目的是让
Record
了与特定日期和产品名称。
the 9 possibilities of item
field in Properties
can be: Properties
中item
字段的9种可能性可以是:
A future query with the same logic will be applied just after to get version by product and by site . 具有相同逻辑的将来查询将在之后应用,以按产品和站点获取版本 。
Thank you for your help! 谢谢您的帮助! And sorry for my bad English :)
对不起,我的英语不好:)
To answer my problem, 为了回答我的问题,
first i have stoped to try user multi .filter
because when i run: 首先,我已
.filter
尝试使用用户multi .filter
因为当我运行时:
records = Record.objects.using("statool").filter(
propertie__item="product",
propertie__value=product,
).filter(
propertie__item="stamp",
propertie__value__gt=str(int(timestamp_from.total_seconds())),
propertie__value__lt=str(int(timestamp_to.total_seconds())),
).count()
After the first .filter
Record objects lost reference to propertie_set
so i can't filter by propertie. 在第一个
.filter
Record对象之后,丢失了对propertie_set
引用,因此我无法按属性进行过滤。
As say @ukemi and @Ralf, using: 如@ukemi和@Ralf,使用:
.filter(
propertie__item="stamp",
propertie__value__gt=str(int(timestamp_from.total_seconds())),
propertie__value__lt=str(int(timestamp_to.total_seconds())),
)
is a really bad idea to have exact query. 进行精确查询是一个非常糟糕的主意。
So this is my solution: 所以这是我的解决方案:
def select_stats(request):
epoch = datetime.date(1970, 1, 1)
period_from = stat_form.cleaned_data.get("period_from")
period_to = stat_form.cleaned_data.get("period_to")
product = stat_form.cleaned_data.get("kit")
timestamp_from = period_from - epoch
timestamp_to = period_to - epoch
timestamp_from = int(timestamp_from.total_seconds())
timestamp_to = int(timestamp_to.total_seconds())
all_product = Propertie.objects.using("statool").filter(
item="product",
value=product
).values_list("id", flat=True)
all_stamp = Propertie.objects.using("statool").annotate(
date=Cast("value", IntegerField())
).filter(
date__gte=timestamp_from,
date__lt=timestamp_to
).values_list("id", flat=True)
all_records = Record.objects.using("statool").filter(
id__in=all_product.intersection(all_stamp)
)
all_recorded_propertie = Propertie.objects.using("statool").filter(id__in=all_records)
all_version = all_recorded_propertie.filter(
id__in=all_records,
item="version"
).values_list("value", flat=True).distinct()
all_site = all_recorded_propertie.filter(
id__in=all_records,
item="site"
).values_list("value", flat=True).distinct()
stats_site = {}
for version in all_version:
stats_site[version] = {}
id_version = all_recorded_propertie.filter(
item="version",
value=version
).values_list("id", flat=True)
for site in all_site:
id_site = all_recorded_propertie.filter(
item="site",
value=site
).values_list("id", flat=True)
stats_site[version][site] = id_version.intersection(id_site).count()
To solve timestamp problem by this way: 通过以下方式解决时间戳问题:
all_stamp = Propertie.objects.using("statool").annotate(
date=Cast("value", IntegerField())
).filter(
date__gte=timestamp_from,
date__lt=timestamp_to
).values_list("id", flat=True)
Thank's to @erikreed from this thread: Django QuerySet Cast 感谢@erikreed这个线程: Django QuerySet Cast
By the way, this is the most efficient way i've found to do my job. 顺便说一句,这是我找到的最有效的工作方式。
But if we run this view we have this runtime: view query runtime 但是,如果运行此视图,则将具有以下运行时: 视图查询运行时
As you can see, every QuerySet are very fast, but intersections between version.id
and site.id
are very long (more than 2 minutes). 如您所见,每个QuerySet都非常快,但是
version.id
和site.id
之间的交集非常长(超过2分钟)。
If someone know a better way to do those query, just let us know :) 如果有人知道做这些查询的更好方法,请告诉我们:)
Hope I help someone. 希望我能帮助别人。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.