• 20 hours
  • Medium

Free online content available in this course.

course.header.alt.is_video

course.header.alt.is_certifying

Got it!

Last updated on 12/12/19

Personnalisez l'affichage des champs

Log in or subscribe for free to enjoy all this course has to offer!

L'interface est presque prête ! Presque... Certains éléments sont encore incohérents. Par exemple, pourquoi le disquaire peut-il ajouter une réservation ?

Dans ce chapitre nous irons un peu plus loin en découvrant comment restreindre les actions qu'un super utilisateur peut effectuer.

Consultation autorisée uniquement

Déclaration des champs en lecture seule.

Une réservation a une date de création unique qui ne peut pas être changée. D'ailleurs vous aurez certainement remarqué que je n'en ai pas parlé jusqu'à maintenant !

Si vous essayez de l'ajouter en tant que champ dans le fieldset, voici ce qui apparaitra :

@admin.register(Booking)
class BookingAdmin(admin.ModelAdmin):
list_filter = ['created_at', 'contacted']
fieldsets = [
(None, {'fields': ['album', 'contact', 'created_at']})
]

Il faut spécifier que ce champ est en lecture seule. Utilisez l'attribut de classe readonly_fields :

admin.py

@admin.register(Booking)
class BookingAdmin(admin.ModelAdmin):
list_filter = ['created_at', 'contacted']
readonly_fields = ["created_at"]

D'ailleurs, on ne devrait pas pouvoir modifier les autres champs non plus ! Modifiez également BookingInline afin que ces informations ne puissent pas être modifiées dans la fiche d'un prospect.

admin.py

@admin.register(Booking)
class BookingAdmin(admin.ModelAdmin):
# ...
readonly_fields = ["created_at", "contact", 'album', 'contacted']
class BookingInline(admin.TabularInline):
### ...
readonly_fields = ["created_at", "contacted", "album"]

Interdiction d'ajouter de nouveaux items

Le disquaire a décidé qu'il ne voulait pas ajouter de réservations par lui-même. Il préfère que les réservations figurant dans la base de données ne concernent que celles effectuées sur internet.

Le client étant roi, exaucez son souhait en utilisant la méthode has_add_permission :

@admin.register(Booking)
class BookingAdmin(admin.ModelAdmin):
# ...
def has_add_permission(self, request):
return False
class BookingInline(admin.TabularInline):
# ...
def has_add_permission(self, request):
return False

Vous y êtes presque !

Affichage d'un lien vers d'autres items

Création d'une méthode générant un lien

Je vous propose d'améliorer la gestion des réservations. A présent, les champs sont en lecture seule mais ce n'est pas suffisant. Vous pourriez ajouter un lien sur le nom du contact et sur celui de l'album pour consulter leur fiche directement, sans avoir à effectuer de recherche.

Django n'a pas prévu ce cas de figure par défaut, il faut donc le créer par vous même ! C’est ce que nous appelons un Mixin : une classe dont héritera un autre objet. Elle n’est pas censée être utilisée seule, mais toujours en lien avec une autre classe. Un peu comme si elle la complétait pour ajouter des fonctionnalités supplémentaires. Pas de panique, nous allons voir cela pas à pas.

Commencez par vous demander ce que vous souhaitez réaliser. Vous voulez remplacer le champ d'une colonne par un lien. Les items de fieldsets et readonly_fields ne sont pas des chaînes de caractères classiques : elles sont interprétées par la suite et exécutées en tant que méthodes. Il est donc possible de passer en paramètre le nom d'une méthode et non celui d'un attribut.

admin.py

from django.utils.safestring import mark_safe
# ...
@admin.register(Booking)
class BookingAdmin(admin.ModelAdmin):
# ...
readonly_fields = ["created_at", "contact", 'album_link', 'contacted']
def album_link(self, booking):
url = "/admin"
return mark_safe("<a href='{}'>{}</a>".format(url, booking.album.title))

Il ne reste plus qu'à récupérer l'URL vers l'album ! La méthode reverse de Django est une des plus connues du framework : elle permet d'obtenir une URL à partir du nom d'une vue.

Exactement comme dans un gabarit lorsque nous avons utilisé {% url 'view_name' %}?

Tout à fait ! En cachette, la méthode url utilise reverse pour connaître le chemin à renvoyer. Lisez le code source de url et URLNode

Mais comment connaitre le nom des vues de l'admin ? Existe-t-il une liste ? Encore une fois, la documentation en or de Django nous donne la solution.

Chaque instance ModelAdmin fournit un ensemble supplémentaire d'URL nommées. Les vues qui modifient un objet partagent le schéma de nom suivant : admin:{{ nom_application }}_{{ nom_modèle }}_change. Par exemple : admin:store_booking_change.

Utilisez cette information pour modifier la méthode en conséquence :

admin.py

from django.core.urlresolvers import reverse
# ...
@admin.register(Booking)
class BookingAdmin(admin.ModelAdmin):
def album_link(self, booking):
path = "admin:store_album_change"
url = reverse(path, args=(booking.album.id,))
return mark_safe("<a href='{}'>{}</a>".format(url, booking.album.title))

Essayez : ça fonctionne !

Ajout d'un Mixin

Afin de réutiliser ce code à plusieurs endroits, créez une nouvelle classe et ajoutez-y la méthode permettant de récupérer l'URL.

admin.py

from django.contrib.contenttypes.models import ContentType
class AdminURLMixin(object):
content_type = ContentType.objects.get_for_model(obj.__class__)
def get_admin_url(self, obj):
return reverse("admin:store_%s_change" % (
content_type.model),
args=(obj.id,))
@admin.register(Booking)
class BookingAdmin(admin.ModelAdmin, AdminURLMixin):
def album_link(self, booking):
url = self.get_admin_url(booking.album)
return mark_safe("<a href='{}'>{}</a>".format(url, booking.album.title))

Vous pouvez désormais l'utiliser sans compter :

admin.py

@admin.register(Booking)
class BookingAdmin(admin.ModelAdmin, AdminURLMixin):
readonly_fields = ["created_at", "contact_link", "album_link", "contacted"]
def contact_link(self, booking):
url = self.get_admin_url(booking.contact)
return mark_safe("<a href='{}'>{}</a>".format(url, booking.contact.name))
def album_link(self, obj):
url = self.get_admin_url(obj.album)
return mark_safe("<a href='{}'>{}</a>".format(url, booking.album.title))
class BookingInline(admin.TabularInline, AdminURLMixin):
readonly_fields = ["created_at", "album_link", "contacted"]
def album_link(self, booking):
url = self.get_admin_url(booking.album)
return mark_safe("<a href='{}'>{}</a>".format(url, booking.album.title))

Dans la page d'édition d'un prospect, album link apparait en tant que colonne. Ce n'est pas très parlant...

Utilisez l'attribut short_description pour modifier cela :

admin.py

class BookingInline(admin.TabularInline, AdminURLMixin):
# ...
def album_link(self, booking):
url = self.get_admin_url(booking.album)
return mark_safe("<a href='{}'>{}</a>".format(url, booking.album.title))
album_link.short_description = "Album"

Bravo, l'interface d'administration est prête ! Vous êtes fin prêt pour la prochaine étape : la préparation de la mise en ligne ! A tout de suite !

Code de ce chapitre

Retrouvez l'intégralité du code sur ce dépôt GitHub.

Example of certificate of achievement
Example of certificate of achievement