我正在尝试设计Extentions of the Django docs' pizza example (screen for pizzas by topping)的解决方案,并且一直在使用Attempt 1。
到目前为止,我的解决方案仅适用于Django barfs之前的两个或三个筛选条件,并抛出 DatabaseError:太多的SQL变量 。我目前的理解是,这是由数据库限制引起的(在本例中为sqlite3)。我也有这样的印象:这个错误是代码不良与数据库配置不足的标志。但是我对SQL或QuerySet机制知之甚少,不知道程序员可以采取什么行动来避免这个错误。
我现在有以下问题:
1。 Django中的SQL变量是什么?
2。这些SQL变量如何在Django中累积?
3。这些SQL变量如何在Django中“刷新”?
4。我在下面的查询代码部分做了什么/不做什么,以至于会抛出这个错误?
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
约束的形式为“amount”,> = | < =“,”value“并放在gte或lte列表中。例如,以下列表表明我们将筛选所有Pizza对象的数据库,使得它们具有:
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()
接下来,在违反“金额”,< =“,”value“约束(通过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)
现在我们已经确定了所有符合lte
规定的约束的topping_amounts对象,我们可以选择那些符合我们gte
约束的对象。这是通过创建一个空的QuerySet topping_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_amounts
QuerySet设置为等于pirma facie可行的ToppingAmount对象,并针对gte
中的下一个约束进行过滤。
topping_amounts = topping_amountsg
在gte
上造成所有topping_amounts
约束后,我们将拥有可行的QuerySet。
Extentions of the Django docs' pizza example (screen for pizzas by topping)关注获取可行的Pizza对象的QuerySet,因此我们从topping_amounts
中的可行ToppingAmount对象中提取它们。
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:SQL变量太多