0

我正在尝试为Django 文档的比萨示例的扩展(通过顶部筛选比萨)设计一个解决方案,并且一直在使用Attempt 1

到目前为止,我的解决方案仅适用于 Django barfs 之前的两个或三个筛选标准,并抛出DatabaseError: too many SQL variables。据我目前的理解,这是由数据库限制(在本例中为 sqlite3)引起的。我也觉得这个错误是糟糕的代码与不充分的数据库配置的标志。但我对 SQL 或 QuerySet 机制的了解还不够,无法知道程序员可以采取哪些措施来导致/避免此错误。

我现在有以下问题:

1. Django中的SQL变量是什么?

2.这些SQL变量在Django中是如何累积的?

3. 这些 SQL 变量如何在 Django 中“刷新”?

4. 我在下面的查询代码部分做了/不做什么,以致预计会引发此错误?

模型.py

from django.db import models

class Topping(models.Model):
  name = models.CharField(max_length=128, primary_key=True)
  units = models.CharField(max_length=4) # e.g. 'g' | 'kg' | 'lb' | 'oz' ...

  # On Python 3: def __str__(self):
  def __unicode__(self):
    return self.name

class ToppingAmount(models.Model):
  pizzaID = models.CharField(max_length=128)
  topping = models.ForeignKey(Topping)
  amount = models.FloatField()

  # On Python 3: def __str__(self):
  def __unicode__(self):
    return self.topping.name

class Pizza(models.Model):
  name = models.CharField(max_length=128, primary_key=True)
  toppings = models.ManyToManyField(ToppingAmount)

  # On Python 3: def __str__(self):
  def __unicode__(self):
    return self.name

查询代码

def screen_query(lte, gte):
  topping_amounts = ToppingAmount.objects.all()

  for c in lte:
    bad = topping_amounts.filter(topping__pk=c[0]).filter(amount__gt=c[1])
    for b in bad:
      topping_amounts = topping_amounts.exclude(pizzaID=b.pizzaID)

  for c in gte:
    topping_amountsg = ToppingAmount.objects.none()
    prima_good = topping_amounts.filter(topping__name=c[0]).filter(amount__gte=c[1])
    for g in prima_good:
      topping_amountsg = topping_amountsg | topping_amounts.filter(pizzaID=g.pizzaID)
    topping_amounts = topping_amountsg

  pizzas = Pizza.objects.none()
  for ta in topping_amounts:
    pizzas = pizzas | Pizza.objects.filter(pk=ta.pizzaID)

  return pizzas

代码说明:

约束的形式为“数量, ">= | <=", "value"并放置在 gte 或 lte 列表中。作为示例,以下列表表明我们将筛选数据库中的所有 Pizza 对象,以便它们具有:

  1. 不超过 30.0 的“意大利辣香肠”
  2. 不超过 63.813 的“菠萝”
  3. 至少 10.0 的“甜椒”
  4. 至少 55 个“火腿”
  5. 至少 10.0 的“培根”
  6. 至少 55 个“鸡”
lte = [["Pepperoni", 30.0], ["Pineapple", 63.813]]
gte = [["Bell Peppers", 10.0], ["Ham", 55], ["Bacon", 10.0], ["Chicken", 55]]

我们通过将所有比萨饼(通过 ToppingAmount)视为候选者来开始查询:

topping_amounts = ToppingAmount.objects.all()  

接下来,识别并排除所有违反“数量”、“<=”、“价值”约束的披萨(通过 topping_amounts):

for c in lte:
  bad = topping_amounts.filter(topping__pk=c[0]).filter(amount__gt=c[1])
  for b in bad:
    topping_amounts = topping_amounts.exclude(pizzaID=b.pizzaID)

现在我们已经确定了所有符合 规定的约束的 topping_amounts 对象lte,我们可以挑选那些也符合我们的gte约束的对象。这是通过创建一个空的 QuerySettopping_amountsg = ToppingAmount.objects.none()并用允许的对象填充它来实现的。

for c in gte:
  topping_amountsg = ToppingAmount.objects.none()
  prima_good = topping_amounts.filter(topping__name=c[0]).filter(amount__gte=c[1])

我们初步认为可行的 ToppingAmount 对象现在位于prima_good. 然而回想一下,披萨有很多配料,因此我们必须收集与每个初步可行的披萨相关的所有 ToppingAmount 对象。

  for g in prima_good:
    topping_amountsg = topping_amountsg | topping_amounts.filter(pizzaID=g.pizzaID)

topping_amountsQuerySet 设置为 pirma facie 可行的 ToppingAmount 对象,并针对 中的下一个约束进行过滤gte

  topping_amounts = topping_amountsg

一旦gte对 施加了所有约束topping_amounts,我们将拥有可行的 QuerySet。

Django 文档的比萨示例的扩展(通过顶部筛选比萨)涉及获取可行比萨对象的 QuerySet,因此我们从可行的 ToppingAmount 对象中提取这些对象topping_amounts

pizzas = Pizza.objects.none()
for ta in topping_amounts:
  pizzas = pizzas | Pizza.objects.filter(pk=ta.pizzaID)

将所有部分放在筛选查询函数中:

def screen_query(lte, gte):
  topping_amounts = ToppingAmount.objects.all()

  for c in lte:
    bad = topping_amounts.filter(topping__pk=c[0]).filter(amount__gt=c[1])
    for b in bad:
      topping_amounts = topping_amounts.exclude(pizzaID=b.pizzaID)

  for c in gte:
    topping_amountsg = ToppingAmount.objects.none()
    prima_good = topping_amounts.filter(topping__name=c[0]).filter(amount__gte=c[1])
    for g in prima_good:
      topping_amountsg = topping_amountsg | topping_amounts.filter(pizzaID=g.pizzaID)
    topping_amounts = topping_amountsg

  pizzas = Pizza.objects.none()
  for ta in topping_amounts:
    pizzas = pizzas | Pizza.objects.filter(pk=ta.pizzaID)

  return pizzas

如果您在 shell 中运行此代码

lte = [["Pepperoni", 30.0], ["Pineapple", 63.813]]
gte = [["Bell Peppers", 10.0], ["Ham", 55], ["Bacon", 10.0], ["Chicken", 55]]

你会得到

文件“/usr/lib/python2.7/site-packages/django/db/backends/sqlite3/base.py”,第 344 行,在执行中 返回 Database.Cursor.execute(self, query, params) DatabaseError: too many SQL 变量

4

0 回答 0