Clés étrangères en django

si un modèle django contient un champ Clé étranger, et si ce champ est affiché en mode liste, alors il apparaît comme texte, au lieu d'afficher un lien au corps étranger.

est-il possible d'afficher automatiquement toutes les clés étrangères sous forme de liens plutôt que de texte plat?

(bien sûr, il est possible de le faire sur un champ par champ, mais est-il un général méthode?)

Exemple:

class Author(models.Model):
    ...

class Post(models.Model):
    author = models.ForeignKey(Author)

maintenant je choisis un ModelAdmin tel que l'auteur apparaît en mode liste:

class PostAdmin(admin.ModelAdmin):
    list_display = [..., 'author',...]

Maintenant en mode liste, le champ auteur utilisera simplement le __unicode__ méthode de l' Author classe pour afficher l'auteur. Sur le dessus de cela, je voudrais un lien pointant vers l'url de l'auteur correspondant dans l'admin du site. Est-ce possible?

Manuel méthode:

par souci d'exhaustivité, j'ajoute la méthode manuelle. Il serait d'ajouter une méthode author_link dans le PostAdmin catégorie:

def author_link(self, item):
    return '<a href="../some/path/%d">%s</a>' % (item.id, unicode(item))
author_link.allow_tags = True

Qui va travailler pour ce domaine particulier, mais qui est ce que je veux. Je veux une méthode générale pour obtenir le même effet. (Un des problèmes est de savoir comment trouver automatiquement le chemin d'accès à un objet sur le site admin de django.)

37
demandé sur Olivier Verdier 2010-03-18 16:55:21

3 réponses

je ne pense pas qu'il existe un mécanisme pour faire ce que vous voulez automatiquement hors de la boîte.

mais en ce qui concerne la détermination du chemin vers une page d'édition admin basée sur l'id d'un objet, tout ce dont vous avez besoin sont deux informations:

a)self.model._meta.app_label

b)self.model._meta.module_name

ensuite, par exemple, pour aller à la page d'édition de ce modèle vous feriez:

'../%s_%s_change/%d' % (self.model._meta.app_label, self.model._meta.module_name, item.id)

regardez django.contrib.admin.options.ModelAdmin.get_urls pour voir comment ils le font.

je suppose que vous pourrait avoir un callable qui prend un nom de modèle et un id, crée un modèle du type spécifié juste pour obtenir l'étiquette et le nom (pas besoin de frapper la base de données) et génère L'URL a ci-dessus.

mais Êtes-vous sûr que vous ne pouvez pas obtenir en utilisant inlines? Cela permettrait à une meilleure interface utilisateur d'avoir tous les composants connexes dans une page...

Edit:

Inlines (lié à docs) permet à une interface d'administration d'afficher un parent-enfant relation en une page au lieu de la diviser en deux.

dans l'exemple Post / Author que vous avez fourni, l'utilisation d'inlines signifierait que la page pour éditer des articles afficherait également un formulaire en ligne pour ajouter/éditer/supprimer des auteurs. Beaucoup plus naturel pour l'utilisateur final.

ce que vous pouvez faire dans la vue Liste administrateur est de créer un callable dans le modèle Post qui rendra une liste d'auteurs séparée par des virgules. Donc, vous aurez votre liste de diffusion montrant les auteurs appropriés, et vous modifiez les auteurs associés à un Post directement dans L'interface d'administration du Post.

9
répondu cethegeek 2014-07-16 08:45:12

je cherchais une solution au même problème et je suis tombé sur cette question... fini par le résoudre moi-même. L'OP n'est peut-être plus intéressée, mais cela pourrait quand même être utile à quelqu'un.

from functools import partial
from django.forms import MediaDefiningClass

class ModelAdminWithForeignKeyLinksMetaclass(MediaDefiningClass):

    def __getattr__(cls, name):

        def foreign_key_link(instance, field):
            target = getattr(instance, field)
            return u'<a href="../../%s/%s/%d">%s</a>' % (
                target._meta.app_label, target._meta.module_name, target.id, unicode(target))

        if name[:8] == 'link_to_':
            method = partial(foreign_key_link, field=name[8:])
            method.__name__ = name[8:]
            method.allow_tags = True
            setattr(cls, name, method)
            return getattr(cls, name)
        raise AttributeError

class Book(models.Model):
    title = models.CharField()
    author = models.ForeignKey(Author)

class BookAdmin(admin.ModelAdmin):
    __metaclass__ = ModelAdminWithForeignKeyLinksMetaclass

    list_display = ('title', 'link_to_author')

remplacer 'partial' par 'curry' de Django si vous n'utilisez pas python >= 2.5.

18
répondu Itai Tavor 2010-07-01 10:50:29

voir https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#admin-reverse-urls

Exemple:

from django.utils.html import format_html
def get_admin_change_link(app_label, model_name, obj_id, name):
    url = reverse('admin:%s_%s_change' % (app_label, model_name),
              args=(obj_id,))
    return format_html('<a href="%s">%s</a>' % (
        url, unicode(name)
    ))
3
répondu adolgarev 2017-04-04 06:27:39