Django ドキュメントのピザの例 (トッピングによるピザの画面) の拡張に対するソリューションを設計しようとしており、 Attempt 1で作業しています。
これまでのところ、私のソリューションは Django barfs の前に 2 つまたは 3 つのスクリーニング基準でのみ機能し、DatabaseError: too many SQL variablesをスローします。これはデータベースの制限 (この場合は sqlite3) が原因であると私は現在理解しています。また、このエラーは、コードが貧弱であることと、データベース構成が不適切であることを示しているという印象もあります。しかし、プログラマーがこのエラーを引き起こしたり回避したりするためにどのようなアクションを実行できるかを知るには、SQL または QuerySet の仕組みについて十分に知りません。
私は今、次の質問があります。
1. Django の SQL 変数とは?
2. これらの SQL 変数は Django でどのように蓄積されますか?
3. これらの SQL 変数は Django でどのように「フラッシュ」されますか?
4. このエラーがスローされると予想されるように、以下のクエリ コード セクションで何を行っていますか?
models.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
コードの説明:
制約の形式は、"amount , ">= | <=", " value"であり、gte または lte リストのいずれかに配置されます。例として、次のリストは、次のようなすべての Pizza オブジェクトについてデータベースをスクリーニングすることを示しています。
- 「ペパロニ」30.0以下
- 「パイナップル」の 63.813 以下
- 10.0 以上の「ピーマン」
- 「ハム」55個以上
- 「ベーコン」10.0以上
- 「ニワトリ」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()
次に、"amount , "<=", " 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)
によって規定された制約に準拠するすべての topping_amounts オブジェクトを識別したので、制約にも準拠するオブジェクトをlte
選択でき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 を、明らかに実行可能な ToppingAmount オブジェクトに等しく設定し、 の次の制約に対してフィルター処理を行いますgte
。
topping_amounts = topping_amountsg
すべてのgte
制約が に適用さtopping_amounts
れると、実現可能な QuerySet が得られます。
Django docs のピザの例 (トッピングによるピザの画面) の拡張は、実行可能な Pizza オブジェクトの 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
このコードをシェルで実行すると
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 行目、実行中 return Database.Cursor.execute(self、query、params) DatabaseError: 多すぎますSQL 変数