我在Django 2.0中有一个查询集问题,经过一些研究,我发现没有任何问题像我的一样。
我认为这是因为我的旧数据库是由我不认识的人创建的。
因此,我有一个如下所示的sqlite数据库:
您已经看到,表属性没有primary_key
,所以我用Django models
命令制作了一个inspectdb
,如下所示:
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)
我将Properties.id
设置为primary_key
,但这是一个ForeignKey
,Django说要将此字段设置为OneToOneField
,这是正常现象和逻辑,但是1 Record
链接到9 Properties
,所以Porpertie.id
不能是unique
,这是我的第一个问题,因为我无法更改数据库。
我的第二个和真实的问题是当我运行此查询时:
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()
此QuerySet
为空,但应返回大约16XXX Record
我不知道会发生什么?
因为我执行以下查询:
records = Record.objects.using("statool").filter(
propertie__item="product",
propertie__value=product,
)
它返回结果,但是第二个过滤器不起作用...
这些请求的目的是使用特定的日期和产品名称来获取Record
。
item
中Properties
字段的9种可能性可以是:
具有相同逻辑的将来查询将立即应用,以通过产品和站点获得版本。
谢谢您的帮助! 对不起,我的英语不好:)
答案 0 :(得分:1)
要回答我的问题,
首先,我停止尝试使用多用户.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()
在第一个.filter
记录对象丢失对propertie_set
的引用之后,我无法按属性进行过滤。
如@ukemi和@Ralf,使用:
.filter(
propertie__item="stamp",
propertie__value__gt=str(int(timestamp_from.total_seconds())),
propertie__value__lt=str(int(timestamp_to.total_seconds())),
)
进行精确查询是一个非常糟糕的主意。
这是我的解决方案:
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()
通过这种方式解决时间戳问题:
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)
感谢@erikreed通过以下线程:Django QuerySet Cast
顺便说一句,这是我找到的最有效的方式。
但是,如果运行此视图,则将具有以下运行时:
view query runtime
如您所见,每个QuerySet都非常快,但是version.id
和site.id
之间的交集很长(超过2分钟)。
如果有人知道更好的查询方法,请告诉我们:)
希望我能帮助别人。