Recherche…


Changer de liste

Disons que vous avez une application myblog simple avec le modèle suivant:

from django.conf import settings
from django.utils import timezone

class Article(models.Model):
    title = models.CharField(max_length=70)
    slug = models.SlugField(max_length=70, unique=True)
    author = models.ForeignKey(settings.AUTH_USER_MODEL, models.PROTECT)
    date_published = models.DateTimeField(default=timezone.now)
    is_draft = models.BooleanField(default=True)
    content = models.TextField()

La liste de changement de Django Admin est la page qui répertorie tous les objets d'un modèle donné.

from django.contrib import admin
from myblog.models import Article

@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
    pass

Par défaut, il utilisera la __str__() (ou __unicode__() si vous êtes sur python2) de votre modèle pour afficher l'objet "name". Cela signifie que si vous ne le remplacez pas, vous verrez une liste d'articles, tous nommés "Objet article". Pour modifier ce comportement, vous pouvez définir la __str__() :

class Article(models.Model):
    def __str__(self):
        return self.title

Maintenant, tous vos articles doivent avoir un nom différent et plus explicite que "Objet article".

Cependant, vous souhaiterez peut-être afficher d'autres données dans cette liste. Pour cela, utilisez list_display :

@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
    list_display = ['__str__', 'author', 'date_published', 'is_draft']

list_display n'est pas limité aux champs et propriétés du modèle. cela peut aussi être une méthode de votre ModelAdmin :

from django.forms.utils import flatatt
from django.urls import reverse
from django.utils.html import format_html

@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
    list_display = ['title', 'author_link', 'date_published', 'is_draft']
    
    def author_link(self, obj):
        author = obj.author
        opts = author._meta
        route = '{}_{}_change'.format(opts.app_label, opts.model_name)
        author_edit_url = reverse(route, args=[author.pk])
        return format_html(
            '<a{}>{}</a>', flatatt({'href': author_edit_url}), author.first_name)

    # Set the column name in the change list
    author_link.short_description = "Author"
    # Set the field to use when ordering using this column
    author_link.admin_order_field = 'author__firstname'

Styles CSS et scripts JS supplémentaires pour la page d'administration

Supposons que vous ayez un modèle Customer simple:

class Customer(models.Model):
    first_name = models.CharField(max_length=255)
    last_name = models.CharField(max_length=255)
    is_premium = models.BooleanField(default=False)

Vous l'enregistrez dans l'administrateur de Django et ajoutez un champ de recherche par first_name et last_name :

@admin.register(Customer)
class CustomerAdmin(admin.ModelAdmin):
    list_display = ['first_name', 'last_name', 'is_premium']
    search_fields = ['first_name', 'last_name']

Après cela, les champs de recherche apparaissent dans la page de la liste des administrateurs avec l'espace réservé par défaut: " mot-clé ". Mais que se passe-t-il si vous souhaitez remplacer cet espace réservé par " Rechercher par nom "?

Vous pouvez le faire en transmettant un fichier Javascript personnalisé dans admin Media :

@admin.register(Customer)
class CustomerAdmin(admin.ModelAdmin):
    list_display = ['first_name', 'last_name', 'is_premium']
    search_fields = ['first_name', 'last_name']
    
    class Media:
        #this path may be any you want, 
        #just put it in your static folder
        js = ('js/admin/placeholder.js', )

Vous pouvez utiliser la barre d'outils de débogage du navigateur pour trouver l'id ou la classe Django définie sur cette barre de recherche, puis écrire votre code js:

$(function () {
   $('#searchbar').attr('placeholder', 'Search by name')
})

De plus, la classe Media vous permet d'ajouter des fichiers CSS avec un objet dictionnaire:

class Media:
    css = {
        'all': ('css/admin/styles.css',)
         }

Par exemple, nous devons afficher chaque élément de la colonne first_name dans une couleur spécifique.
Par défaut, la colonne create table de Django pour chaque élément de list_display , toutes les balises <td> auront la classe css comme field-'list_display_name' , dans notre cas il s'agira de field_first_name

.field_first_name {
     background-color: #e6f2ff;
 }

Si vous souhaitez personnaliser d'autres comportements en ajoutant JS ou certains styles css, vous pouvez toujours vérifier les identifiants et les classes d'éléments dans l'outil de débogage du navigateur.

Traiter des clés étrangères référençant de grandes tables

Par défaut, Django rend les champs ForeignKey comme une entrée <select> . Cela peut entraîner un chargement très lent des pages si vous avez des milliers ou des dizaines de milliers d'entrées dans la table référencée. Et même si vous n’avez que des centaines d’entrées, il est très difficile de rechercher une entrée particulière parmi toutes.

Un module externe très pratique pour cela est django-autocomplete-light (DAL). Cela permet d'utiliser des champs de saisie semi-automatique au lieu des champs <select> .

exemple de django-autocomplete-light

views.py

from dal import autocomplete

class CityAutocomp(autocomplete.Select2QuerySetView):
    def get_queryset(self):
        qs = City.objects.all()
        if self.q:
            qs = qs.filter(name__istartswith=self.q)
        return qs

urls.py

urlpatterns = [
    url(r'^city-autocomp/$', CityAutocomp.as_view(), name='city-autocomp'),
]

forms.py

from dal import autocomplete

class PlaceForm(forms.ModelForm):
    city = forms.ModelChoiceField(
        queryset=City.objects.all(),
        widget=autocomplete.ModelSelect2(url='city-autocomp')
    )

    class Meta:
        model = Place
        fields = ['__all__']

admin.py

@admin.register(Place)
class PlaceAdmin(admin.ModelAdmin):
    form = PlaceForm


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow