2012-06-30 7 views
2

Mon désir est d'avoir un modèle d'emplacement commun, puis de faire référence aux différents modèles de niveau supérieur qui ont besoin d'un emplacement.Django Admin Inline et Schema Design

Je souhaite présenter mon utilisateur à l'administrateur avec un formulaire à plusieurs parties (une ligne) qui lui permet d'entrer les informations de niveau supérieur pour l'éditeur et le bâtiment, ainsi que les informations d'emplacement pour chacun. Le système en ligne ne semble pas vouloir fonctionner de cette façon. De toute évidence, je fais quelque chose de très mal, parce que cela me semble être un problème très standard. Est-ce que ma conception de schéma est borked? Est-ce que j'utilise stupidement le système inline? Je ne veux pas faire des sous-classes de Location pour chaque objet de niveau supérieur, parce que je veux manipuler des emplacements de manière différente indépendamment des objets de haut niveau qui les possèdent (une liste de diffusion ou une recherche géographique peut-être)

models.py: 
... 
class Location(models.Model): 
    """ 
    A geographical address 
    """ 
# Standard Location stuff 
    address_line1 = models.CharField("Address line 1", max_length = 45, null=True, blank=True) 
    ... 

class Publisher(models.Model): 
    """ 
    Contains Publisher information for publishers of yearbooks. Replaces Institution from 1.x 
    """ 
    name = models.CharField(max_length=100, null=False, help_text="Name of publisher, e.g. University of Kansas") 
    groups = models.ManyToManyField(Group, help_text="Select groups that this publisher owns. Usually just one, but multiple groups are possible.") 
    is_active = models.BooleanField(help_text="Check this box to enable this publisher.") 
    location = models.OneToOneField(Location) 
    ... 

class Building(models.Model): 
    """ 
    Contains Building Information 
    """ 
    name = models.CharField(max_length=100, null=False, help_text="Name of building, e.g. Physical Sciences") 
    is_active = models.BooleanField(help_text="Check this box to enable this building.") 
    location = models.OneToOneField(Location) 
    ... 

admin.py: 
... 
class LocationInline(generic.GenericStackedInline): 
    model = Location 
    max_num = 1 
    extra = 1 

class PublisherAdmin(admin.ModelAdmin): 
    model = Publisher 
    inlines = [ LocationInline, 
    ] 

class BuildingAdmin(admin.ModelAdmin): 
    model = Building 
    inlines = [ LocationInline, 
    ] 

admin.site.register(Publisher, PublisherAdmin) 
admin.site.register(Building, BuildingAdmin) 

Je peux forcer la ligne à charger et présente en ajoutant ceci au modèle Lieu:

# Support reverse lookup for admin 
    object_id = models.PositiveIntegerField() 
    content_type = models.ForeignKey(ContentType) 
    of   = generic.GenericForeignKey('content_type', 'object_id') 

Mais quand je fais cela, même si je reçois un objet en ligne, et peut le modifier, la relation semble en arrière pour moi, avec Location stockant un identifiant à l'objet qui l'a créé.

Toute aide est la bienvenue, soit un changement de schéma recommandé pour que tout fonctionne à merveille (comme Django le fait si bien) ou une astuce pour rendre le truc apparemment rétrograde logique.

Répondre

1

Premièrement, je pense que vous voulez ForeignKey, pas OneToOneField. Sinon, vous pouvez aussi simplement ajouter vos champs de localisation aux modèles Publisher et Building. Ensuite, vous aurez simplement une liste déroulante pour choisir l'emplacement et un lien pour en ajouter un nouveau si nécessaire dans le bâtiment et l'administrateur de l'éditeur. Si vous voulez vraiment avoir une instance de localisation par bâtiment/éditeur, vous ne pourrez pas l'éditer en ligne car un modèle en ligne doit avoir un ForeignKey pointant vers le modèle parent, sauf si vous ajoutez le générique clé étrangère. Ce n'est pas "en arrière" - c'est une option valide quand vous voulez qu'un objet puisse se joindre à un autre, quel que soit le type.

+0

Voilà ce qui me manquait Greg. La notion d'attacher _itself_ à un autre objet, sans que l'objet 'parent' ait une quelconque conscience. Mon champ OneToOne est superflu dans cette situation. Je l'ai. Je vous remercie. –

1

Quand il s'agit de modèle de domaine, il n'existe pas de «One Right Way» pour le faire, cela dépend des exigences de votre application spécifique.

WRT/votre problème:

Le champ OneToOne limite vos modèles à un seul endroit par exemple de modèle, qui (comme Greg mentionné) n'est pas sur le plan conceptuel très différent de juste coller directement les champs de l'emplacement dans le modèle. wrt/DRY/factorisation/réutilisation etc, vous pouvez obtenir cela en utilisant l'héritage du modèle aussi, ayant un modèle abstrait (ou éventuellement concret si cela a du sens pour votre application). La solution ForeignKey restreint toujours vos modèles Publisher et Building à un seul emplacement (qui peut être ou ne pas être ce que vous voulez), mais un emplacement donné peut être partagé entre différentes instances Publisher et/ou bâtiment. Cela signifie que l'édition d'un emplacement donné reflétera sur toutes les instances liées (méfiez-vous des effets secondaires indésirables ici). L'utilisation d'une GenericForeignKey dans le modèle Location signifie qu'une instance d'emplacement donnée appartient à un et un seul objet apparenté.Aucun effet secondaire surprenant comme avec la solution ci-dessus mais vous pouvez avoir des emplacements dupliqués (un pour le bâtiment, un pour l'éditeur) avec les mêmes valeurs, et vous ne pourrez pas rechercher tous les objets associés pour un emplacement spécifique (ou pas si facilement au moins). En outre, cela n'empêchera pas une instance de Publisher ou de bâtiment d'avoir plusieurs emplacements, ce qui peut être une fois de plus acceptable ou non. wrt/Emplacement instance "stocker l'id" de l'objet auquel ils appartiennent, eh bien, c'est vraiment ce que ce choix de conception signifie: un emplacement "appartient à" un autre objet, point.

Dans tous les cas, concevoir autour du comportement par défaut de l'application d'administration de Django n'est probablement pas la chose la plus sage à faire. Vous devez d'abord décider ce qui est logique pour cette application (et vous pouvez avoir des besoins différents pour les éditeurs et les bâtiments), puis éventuellement étendre l'administrateur pour répondre à vos besoins.

+0

Merci pour la réponse. Je suis conscient des limitations générales des FK et OneToOne. Greg dans la réponse ci-dessous m'a trié. C'était un raccrochage conceptuel de ma part, pensant que je devais avoir une référence en avant de mon parent à l'enfant, alors qu'en fait, ce que je veux vraiment, c'est un enfant qui peut attacher _itself_ à un parent arbitraire. –