https://docs.djangoproject.com/en/dev/topics/db/models/#many-to-many-relationshipsで、Django チームはピザとトッピングのコンテキストで多対多の関係について説明しています。私は彼らの例を参考にして、自分のデータをモデリングする際に抱えている概念上の問題の解決策を見つけようとしました。
このスタック オーバーフローの投稿の結果として達成しようとしていることを正確に説明するために、次の (架空の) 文法を考えてみましょう。
TOPPING = {'a'..'z' | 'A'..'Z'};
FLOAT = {'0'..'9'}, ['.', {'0'..'9'}]; (* Non-negative numbers only *)
QUERY = "Hey Django, find me all of the pizzas in the database such that:",
{ "(", (TOPPING), (">=" | "<=" | "=="), FLOAT, ") &&" },
"(", (TOPPING, (">=" | "<=" | "=="), FLOAT, ")";
私が観察しようとしているのは、QUERY の行に沿って何かを発行して返された QuerySet です。その内容が示すように、Django から、スクリーニング基準を満たすすべての Pizza オブジェクトを含む QuerySet を返してもらいたいと考えています。models.py がどのように見えるべきか、または実際のクエリがどのように見えるべきかについて確信が持てません。上記の疑似クエリと返される結果を説明するのに十分な経験しかありません。
事前に感謝します。あなたの提案を読むのを楽しみにしています。
追加情報
私の特定の状況では、初期データがロードされた後はデータベースに書き込まれないことに注意してください。読み取りは常に非常に頻繁に行われます。
私は生の SQL を使用することにオープンですが、私の好みは Django QuerySet API の使用です。
ソリューションの試行 1:
モデルに ToppingAmount(models.Model) クラスを追加しました。金額のフロートと、ピザとトッピングを金額に関連付ける 2 つの外部キーを指定しました。
from django.db import models
class Topping(models.Model):
name = models.CharField(max_length=128)
# On Python 3: def __str__(self):
def __unicode__(self):
return self.name
class Pizza(models.Model):
name = models.CharField(max_length=128)
toppings = models.ManyToManyField(Topping, through='ToppingAmount')
# On Python 3: def __str__(self):
def __unicode__(self):
return self.name
class ToppingAmount(models.Model):
topping = models.ForeignKey(Topping)
pizza = models.ForeignKey(Pizza)
amount = models.FloatField()
units = models.CharField(max_length=4) # e.g. 'g' | 'kg' | 'lb' | 'oz' ...
上記のモデルを使用すると、(たとえば) を実行しToppingAmount.objects.filter(topping__name='foo').filter(amount__gt=bar)
てすべてのToppingAmountオブジェクトを見つけて、ピザに少なくとも 1 グラムの foo が含まれるようにすることができます。
残念ながら、トッピングに少なくともバーグラムの「ピッポ」があるようなすべてのToppingAmountToppingAmount.objects.filter(pizza__name='pippo').filter(amount__gt=bar)
オブジェクトを見つけるひねくれたものも可能にします。
これは、このモデルと単純なフィルターで得られた範囲です。この QuerySet にはToppingAmountオブジェクトしか含まれていないため、結果の QuerySet を他のトッピング (またはピザ;) および量に関してフィルタリングすることはできません。この QuerySet 内のすべての ToppingAmount オブジェクトには、同じトッピングまたは同じピザが含まれます。それらのすべての量 (トッピングまたはピザを説明するために解釈されるかどうか) も、filter(amount...)
.
さらに、ここで多対多の関係を使用しても具体的なメリットはありません。他のすべてを同じに保ちながら、Pizza クラスからトッピングを削除すると、可能なクエリからの同一の json ダンプと同一のユーティリティを備えたデータベースが得られます。
試行 2:
146 種類のトッピングすべての列を含むピザ テーブルを作成します。
from django.db import models
class Topping(models.Model):
name= modles.CharField(max_length=128)
units = models.CharField(max_length=4) # e.g. 'g' | 'kg' | 'lb' | 'oz' ...
class Pizza(models.Model):
name = models.CharField(max_length=128)
topping1_amount = models.FloatField()
.
.
.
topping146_amount = models.FloatField()
# On Python 3: def __str__(self):
def __unicode__(self):
return self.name
このソリューションは、必要または望ましいとは思わない大きくてまばらなテーブルを作成するため、慎重に信頼しています(コメントを歓迎します)。一方、このモデルのクエリを作成するのは非常に簡単です。Pizza.objects.filter(topping1_amount__gt=20).filter(topping2_amount__lt=15)...