4

与えられた:

from django.db import models

class Food(models.Model):
     """Food, by name."""
     name = models.CharField(max_length=25)

class Cat(models.Model):
     """A cat eats one type of food"""
     food = models.ForeignKey(Food)

class Cow(models.Model):
     """A cow eats one type of food"""
     food = models.ForeignKey(Food)

class Human(models.Model):
     """A human may eat lots of types of food"""
     food = models.ManyToManyField(Food)

クラス Food だけが与えられた場合、「逆の関係」を持つすべてのクラスのセットを取得するにはどうすればよいでしょうか。つまり、クラスFoodが与えられた場合、クラスCatCow、およびHumanを取得するにはどうすればよいでしょうか。

Food には、 Food.cat_setFood.cow_set、およびFood.human_setの 3 つの「逆の関係」があるため、可能だと思います。

助けてくれてありがとう!

4

2 に答える 2

14

ソースコードを掘り下げると、次のことが明らかになりました。

ジャンゴ/デシベル/モデル/options.py:

def get_all_related_objects(self, local_only=False):

def get_all_related_many_to_many_objects(self, local_only=False)

そして、上記のモデルでこれらの関数を使用すると、仮説的に次のようになります。

>>> Food._meta.get_all_related_objects()
[<RelatedObject: app_label:cow related to food>,
    <RelatedObject: app_label:cat related to food>,]

>>> Food._meta.get_all_related_many_to_many_objects()
[<RelatedObject: app_label:human related to food>,]

# and, per django/db/models/related.py
# you can retrieve the model with
>>> Food._meta.get_all_related_objects()[0].model
<class 'app_label.models.Cow'>

: Model._meta は「不安定」であり、おそらく Django-1.0 以降の世界では信頼すべきではないと聞いています。

読んでくれてありがとう。:)

于 2008-11-11T02:00:20.570 に答える
7

また

A)複数のテーブル継承を使用して、Cat、Cow、および Human が継承する「Eater」基本クラスを作成します。

B) Food を他のモデルにリンクできるGeneric Relationを使用します。

これらは十分に文書化され、公式にサポートされている機能です。独自のコードをクリーンに保ち、回避策を避け、将来もサポートされるようにするために、それらに固執することをお勧めします。

-- 編集 (別名「評判の娼婦になる方法」)

したがって、ここにその特定のケースのレシピがあります。

Cat、Cow、および Human の個別のモデルが絶対に必要であると仮定しましょう。実際のアプリケーションでは、「カテゴリ」フィールドが機能しない理由を自問する必要があります。

一般的なリレーションを介して「本当の」クラスに到達する方が簡単なので、B の実装を次に示します。Person、Cat、または Cow にその「food」フィールドを含めることはできません。そうしないと、同じ問題に遭遇することになります。そこで、中間の「FoodConsumer」モデルを作成します。インスタンスに複数の食品が必要ない場合は、追加の検証テストを作成する必要があります。

from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic

class Food(models.Model):
     """Food, by name."""
     name = models.CharField(max_length=25)

# ConsumedFood has a foreign key to Food, and a "eaten_by" generic relation
class ConsumedFood(models.Model):
    food = models.ForeignKey(Food, related_name="eaters")
    content_type = models.ForeignKey(ContentType, null=True)
    object_id = models.PositiveIntegerField(null=True)
    eaten_by = generic.GenericForeignKey('content_type', 'object_id')

class Person(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    birth_date = models.DateField()
    address = models.CharField(max_length=100)
    city = models.CharField(max_length=50)
    foods = generic.GenericRelation(ConsumedFood)

class Cat(models.Model):
    name = models.CharField(max_length=50)
    foods = generic.GenericRelation(ConsumedFood)    

class Cow(models.Model):
    farmer = models.ForeignKey(Person)
    foods = generic.GenericRelation(ConsumedFood)    

さて、それを実証するために、この動作するdoctestを書きましょう:

"""
>>> from models import *

Create some food records

>>> weed = Food(name="weed")
>>> weed.save()

>>> burger = Food(name="burger")
>>> burger.save()

>>> pet_food = Food(name="Pet food")
>>> pet_food.save()

John the farmer likes burgers

>>> john = Person(first_name="John", last_name="Farmer", birth_date="1960-10-12")
>>> john.save()
>>> john.foods.create(food=burger)
<ConsumedFood: ConsumedFood object>

Wilma the cow eats weed

>>> wilma = Cow(farmer=john)
>>> wilma.save()
>>> wilma.foods.create(food=weed)
<ConsumedFood: ConsumedFood object>

Felix the cat likes pet food

>>> felix = Cat(name="felix")
>>> felix.save()
>>> pet_food.eaters.create(eaten_by=felix)
<ConsumedFood: ConsumedFood object>

What food john likes again ?
>>> john.foods.all()[0].food.name
u'burger'

Who's getting pet food ?
>>> living_thing = pet_food.eaters.all()[0].eaten_by
>>> isinstance(living_thing,Cow)
False
>>> isinstance(living_thing,Cat)
True

John's farm is in fire ! He looses his cow.
>>> wilma.delete()

John is a lot poorer right now
>>> john.foods.clear()
>>> john.foods.create(food=pet_food)
<ConsumedFood: ConsumedFood object>

Who's eating pet food now ?
>>> for consumed_food in pet_food.eaters.all():
...    consumed_food.eaten_by
<Cat: Cat object>
<Person: Person object>

Get the second pet food eater
>>> living_thing = pet_food.eaters.all()[1].eaten_by

Try to find if it's a person and reveal his name
>>> if isinstance(living_thing,Person): living_thing.first_name
u'John'

"""
于 2008-11-11T03:48:52.053 に答える