2008-11-11 60 views
4

考慮:Django中的模型如何獲得具有反向關係的所有類的集合?

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.cat_setFood.cow_setFood.human_set

幫助讚賞&謝謝!

回答

7

要麼

A)使用multiple table inheritance,並創建一個 「食」 的基類,即貓,牛和人繼承。 B)使用Generic Relation,其中Food可以鏈接到任何其他模型。

這些都是有據可查的和官方支持的功能,您最好堅持讓它們保持自己的代碼清潔,避免變通方法並確保將來仍然支持它。

- EDIT(又名「如何成爲一個聲譽妓女」)

所以,這裏是特定情況下的配方。

讓我們假設你絕對需要貓,牛和人的單獨模型。在現實世界的應用程序中,您想問自己爲什麼「類別」字段不能完成這項工作。

通過泛型關係可以更容易地到達「真實」類,所以這裏是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' 

""" 
+0

嗨文森特,爲響應感謝。如何正確使用MTI或GR來回答這個問題將非常感謝:)。 – 2008-11-11 17:14:09

14

在源代碼中一些挖透露:

的Django/DB /模型/ 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世界依靠。

感謝您的閱讀。 :)

相關問題