0

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 オブジェクトについてデータベースをスクリーニングすることを示しています。

  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()  

次に、"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_amountsQuerySet を、明らかに実行可能な 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 変数

4

0 に答える 0