2010-07-21 3 views
2

J'ai un multi modèle avec différentes relations OneToOne de différents modèles à un seul parent. Considérez cet exemple:Django multi-modèle: relations de traçage

class Place(models.Model): 
    name = models.CharField(max_length=100) 
    address = models.CharField(max_length=100) 
    ... 

class Restaurant(models.Model): 
    place = models.OneToOneField(Place) 
    ... 

class Shop(models.Model): 
    place = models.OneToOneField(Place) 
    ... 

Peu importe si le modèle ci-dessus est logique dans le scénario de la vie réelle, comment quelqu'un peut-il identifier si un objet de la place a une relation avec l'un des autres modèles, en vue django?

Répondre

1

Dans un modèle, vous pouvez dire

{% if place.restaurant %} 
    <!-- stuff goes here --> 
{% endif %} 

La raison est que OneToOneField entrées créent en fait un attribut dans le modèle qu'ils font référence. En code Python normal, en disant place.restaurant où aucun restaurant n'est défini jettera une exception, mais les modèles avaleront de telles exceptions.

Si vous avez besoin de faire quelque chose comme cela dans le code Python, la façon la plus simple à comprendre est l'envelopper dans un try/except:

place = Place.objects.all()[0] 
try: 
    restaurant = place.restaurant 
    # do something with restaurant 
except ObjectDoesNotExist: 
    # do something without restaurant 

EDIT: Comme je le dis mon commentaire, si vous voulez seulement un Place soit un Restaurant ou un Shop mais jamais les deux, alors vous ne devriez pas utiliser OneToOneField et devrait plutôt utiliser model inheritance.

En supposant qu'un Place pourrait avoir deux ou plusieurs autres possibilités, je vous recommande de faire quelque chose comme ceci:

class Place(Model): 
    # define your fields here 

    # you could generate this automatically with trickery 
    OTHER_MODELS = ["restaurant", "shop"] 

    @property 
    def relationships(self): 
     if not hasattr(self, "_relationships"): 
      self._relationships = {} 
      for attr in OTHER_MODELS: 
       try: 
        self._relationshops[attr] = getattr(self, attr) 
       except ObjectDoesNotExist: 
        pass 
     return self._relationships 

Ce qui précède vous laisser dire place.relationships et retourner un dictionnaire qui ressemblait

{"restaurant": <Restaurant Object>, "shop": <Shop Object>} 

bien que l'un d'eux ou les deux puissent manquer, selon qu'ils existent. Ce serait plus facile de travailler avec que de devoir attraper une exception potentielle chaque fois que vous inversez la relation OneToOneField.

+0

C'est la voie à suivre s'il n'y avait pas de multiples possibilités pour un seul objet Lieu-à-dire Shop et restaurant. sinon, vous devrez parcourir tous les «sous-modèles». ou ai-je oublié quelque chose? – msebai

+0

@ msebai: Oui, vous devrez parcourir les autres possibilités. Si votre conception appelle 'Place' pour n'être jamais qu'un' Restaurant' ou un 'Shop' mais pas les deux, vous ne devriez pas utiliser' OneToOneField' et devriez plutôt utiliser l'héritage du modèle: http: //docs.djangoproject. com/fr/1.2/topics/db/models/# héritage-de-modèle –

+1

Je suppose que l'héritage a beaucoup de sens ici. J'ai juste besoin de savoir comment django va traiter ça au niveau DB. Merci beaucoup pour votre temps. – msebai

0

Parce que Restaurant a une clé étrangère pointant dans Place, il laisse un champ related name de la classe, de sorte que la classe (Place) à pointé peut trouver son contenu:

# python 
import yourproject.settings 
from django.db.models.base import ObjectDoesNotExist 
try: 
    r = place.restaurant_set.get() 
    do_something(r.restaurant_field) 
except ObjectDoesNotExist: 
    print "place has no restaurant" 

Et à partir d'un modèle, en supposant que vous avez accès à placeobject de votre contexte d'une certaine manière:

{% with placeobject.restaurant_set.get as r %} 
    {% if r %} 
    {{ r.restaurant_field }} 
    {% else %} 
    No restaurant 
    {% endif %} 
{% endwith %}