2010-07-05 20 views
2

Je crée un CMS simple en django, avec plusieurs "modules" (chacun en tant qu'application django). J'ai mis en place les modèles suivants:Héritage Django et Permaliens

class FooObject(models.Model): 
    id = models.SlugField(primary_key=True) 
    name = models.CharField(max_length=255) 
    creator = models.ForeignKey(auth.models.User, editable=False, related_name="createdby") 

class FooPage(FooObject): 
    content = models.TextField(blank=True, null=True) 

    @models.permalink 
    def get_absolute_url(self): 
     return ('page',(), {'page_id':self.id} 

class FooSubitem(FooObject): 
    parent = models.ForeignKey(FooPage, related_name='subitems') 

, je crée dans chacun des modules une sous-classe de FooPage, et au moins une sous-classe de FooSubitem, par exemple

# in FooBlog.models 
class FooBlog(FooPage): 
    owner = models.ForeignKey(auth.models.User, editable=False) 

    @models.permalink 
    def get_absolute_url(self): 
     return ('blog',(), {'blog_id':self.id}) 

class FooPost(FooSubitem): 
    post_time = models.DateTimeField(auto_now_add=True) 

et

# in FooGallery.models 
class FooGallery(FooPage): 
    location = models.CharField(max_length=255) 

    @models.permalink 
    def get_absolute_url(self): 
     return ('gallery',(), {'gallery_id':self.id}) 

class FooImage(FooSubitem): 
    image_file = models.ImageField(upload_to='foogallery') 

Ce sont des simplifications, mais devrait vous donner une bonne idée de ce que je suis en train de faire. Dans les admins pour FooPost et FooImage, je restreindre la liste de sélection parente à leurs pages parentes correspondantes.

Mon problème se pose lorsque j'essaie de les utiliser dans un modèle. Dans chaque vue, je donne les résultats suivants:

page_list = FooPage.objects.all() 

qui retourne une liste de tous les FooPages, des deux types FooBlog et FooGallery. Cependant, quand j'itérer cette liste:

{% for page in page_list %}{{ page.get_absolute_url }}{% endfor %} 

retourne le modèle url « page », pas le modèle url « blog » ou « galerie ».

Comment est-ce que je fais ce travail sans avoir à réécrire le code quand je veux ajouter un module FooCalendar plus tard? Je veux m'assurer que cela fonctionne avec n'importe quel module possible.

Merci,

  • Lexo
+1

Il est étrange que cela n'utilise pas la fonction de sous-classes pour retourner l'URL (Il ne retourne FooBlog et FooGallery dans la liste, à droite) .. vous devrez peut-être définir les classes 'FooBlog' et' FooGallery' en tant que modèles de proxy.Les modèles de proxy sont utilisés lorsque vous conservez la même base de données pour les modèles, mais vous souhaitez ajuster certaines choses comme la commande, et peut-être la fonctionnalité 'get_absolute_url'. Vérifiez-les: http://docs.djangoproject.com/fr/1.2/topics/db/models/#id8 - Faites-moi savoir si cela fonctionne pour vous. – Bartek

+0

Merci pour l'info. Je vais regarder dans les modèles de proxy. – Lexo

+0

Je ne pense pas que les modèles de proxy sont ce dont j'ai besoin. Les sous-classes individuelles telles que FooImage doivent être associées à des champs supplémentaires. Les classes abstraites seraient parfaites, mais j'ai besoin de la relation parent/enfant entre FooPages et FooSubitems pour être là, et vous ne pouvez pas spécifier de clés étrangères sur les classes abstraites. – Lexo

Répondre

0

FooPage.objects.all() retourne tous les objets de type FooPage, ces objets seront mélange de lignes de table de données sous-jacente pour FooPage, FooBlog, FooGallery. Pour obtenir l'URL correcte, vous devez obtenir l'objet FooBlog ou FooGallery, par exemple.

page.fooblog.get_absolute_url() 

il peut jeter FooBlog.DoesNotExist erreur si la page est tout simplement un objet page-à-dire créé par FooPage, afin d'obtenir urls correctes, vous pouvez faire quelque chose comme ça

urls = [] 
    for page in FooPage.objects.all(): 
     try: 
      page = page.fooblog 
     except FooBlog.DoesNotExist: 
      pass 

      urls.append(page.get_absolute_url()) 

Sinon, vous pouvez essayer de faire FooPage un abstractclass si vous ne voulez pas que FooPage soit une vraie table.

+0

Merci Anurag. Mon problème est que je ne connais pas les applications du module (par exemple FooBlog, FooGallery) que j'aurai installées ou que je pourrais installer dans le futur. Si je finis par créer 10 applications différentes ou plus (ce qui est tout à fait possible), je ne veux pas avoir à réécrire mon code pour inclure des contrôles pour chaque type de FooPage. De plus, cela semble terriblement inefficace et quelque chose que je devrais pouvoir faire par programmation. Existe-t-il un moyen de "descendre" vers la sous-classe la plus spécifique? – Lexo

+0

En outre, j'ai essayé d'utiliser des classes abstraites, mais comme FooSubitems doit avoir des parents FooPage, et vous ne pouvez pas spécifier une clé étrangère à une classe abstraite, cela ne fonctionne pas. – Lexo

+0

peut être que vous pouvez écrire une fonction générique qui fait la même chose, à savoir essayer d'obtenir des objets de classe dérivés si possible, vous pouvez le faire en utilisant un gestionnaire de modèle personnalisé (http://www.djangoproject.com/documentation/models/custom_managers /) –

1

Vous pouvez éviter d'ajouter un champ de type de contenu en utilisant InheritanceManager de django-model-utils.

Ensuite, si vous appelez .select_subclasses sur un queryset, il downcaster tous les objets, par exemple:

FooPage.objects.select_subclasses().all()