Work on the administration panels
This commit is contained in:
parent
c0bec85c6f
commit
3d860d6a6b
|
@ -91,12 +91,12 @@ from django.contrib import admin
|
|||
from .models import Item, WishList <1>
|
||||
|
||||
|
||||
@register(Item)
|
||||
@admin.register(Item)
|
||||
class ItemAdmin(admin.ModelAdmin): <2>
|
||||
pass
|
||||
|
||||
|
||||
@register(WishList)
|
||||
@admin.register(WishList)
|
||||
class WishListAdmin(admin.ModelAdmin):
|
||||
pass
|
||||
```
|
||||
|
@ -162,7 +162,7 @@ Le titre peut être modifié de deux manières :
|
|||
* Soit en ajoutant l’assignation suivante dans le fichier `urls.py` :
|
||||
|
||||
```python
|
||||
admin.site.site_header = "SuperBook Secret Area`.
|
||||
admin.site.site_header = "Gwift Secret Area"
|
||||
```
|
||||
|
||||
=== Prefetch
|
||||
|
@ -178,31 +178,70 @@ La solution consiste à utiliser la propriété `list_select_related` de la clas
|
|||
|
||||
=== L’affichage
|
||||
|
||||
Comme l’interface d’administration fonctionne (en trèèèès) gros comme un
|
||||
CRUD auto-généré, nous trouvons par défaut la possibilité de :
|
||||
Comme l’interface d’administration fonctionne (en trèèèès) gros comme un CRUD auto-généré, nous trouvons par défaut la possibilité de :
|
||||
|
||||
. Créer de nouveaux éléments
|
||||
. Lister les éléments existants
|
||||
. Modifier des éléments existants
|
||||
. Supprimer un élément en particulier.
|
||||
|
||||
Les affichages sont donc de deux types : en liste et au détail.
|
||||
image::django/admin/django-admin-base.png[align="center"]
|
||||
|
||||
Les affichages sont donc de deux types :
|
||||
|
||||
* En liste, pour afficher et filtrer sur certains éléments
|
||||
* Les détails d'un élément.
|
||||
|
||||
==== Affichage en liste
|
||||
|
||||
Pour les affichages en liste, le plus simple consiste à jouer sur la propriété `list_display`, afin de personnaliser les informations que nous visualiserons dans le tableau affiché :
|
||||
Par défaut, l'affichage en liste se base sur la propriété `__str__()` de chaque élément, afin d'en proposer une représentation textuelle.
|
||||
Cette représentation est cependant totalement impersonnelle, n'a aucun intérêt et ce sera sans doute la première chose que vous modifierez dans votre projet tout neuf.
|
||||
|
||||
image::django/admin/django-base-list.png[align="center"]
|
||||
|
||||
Pour ce type d'affichage, le plus simple consiste à jouer sur la propriété `list_display`, afin de personnaliser les informations que nous visualiserons dans le tableau affiché :
|
||||
|
||||
```python
|
||||
[...]
|
||||
|
||||
@admin.register(Item)
|
||||
class ItemAdmin(admin.ModelAdmin): <2>
|
||||
list_display = ("__str__", "wishlist_name")
|
||||
list_filter = ("wishlist_name",)
|
||||
|
||||
[...]
|
||||
```
|
||||
|
||||
image::django/admin/django-list_display.png[align="center"]
|
||||
|
||||
[WARNING]
|
||||
====
|
||||
Il n'est pas possible d'afficher tout et n'importe quoi sans un peu de configuration.
|
||||
Par exemple, si nous souhaitons afficher le nom de la liste dont dépend l'élément ou une propriété relative, il est nécessaire de passer par une méthode au niveau de la classe d'administration.
|
||||
|
||||
```python
|
||||
|
||||
@admin.register(Item)
|
||||
class ItemAdmin(admin.ModelAdmin):
|
||||
def wishlist_name(self, obj): <1>
|
||||
return obj.wishlist.name
|
||||
|
||||
list_display = ("__str__", "wishlist_name") <2>
|
||||
|
||||
|
||||
```
|
||||
<1> Nous définissons une méthode `wishlist_name`
|
||||
<2> à laquelle nous faisons référence dans la propriété `list_display`.
|
||||
|
||||
L'objectif ici est de pouvoir *tester* tout comportement qui sortirait des sentiers battus.
|
||||
====
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Par défaut, la première colonne va accueillir le lien vers le formulaire d’édition. Nous pouvons donc modifier ceci, voire créer de nouveaux liens vers d’autres éléments en construisant des URLs dynamiquement.
|
||||
====
|
||||
|
||||
|
||||
==== Affichage des détails d'un élément
|
||||
|
||||
*... montrer le regroup_by et les collapse.*
|
||||
|
||||
=== Filtres
|
||||
==== Filtres de listes
|
||||
|
||||
Chaque liste permet de spécifier des filtres spécifiques; ceux-ci peuvent être :
|
||||
|
||||
|
@ -211,16 +250,61 @@ Chaque liste permet de spécifier des filtres spécifiques; ceux-ci peuvent êtr
|
|||
. *Verticaux* (`filter_vertical`)
|
||||
. *Temporels* (`date_hierarchy`)
|
||||
|
||||
==== Appliqués à la liste
|
||||
===== Appliqués à la liste
|
||||
|
||||
==== Horizontaux
|
||||
La version la plus simple des filtres consiste à définir une propriété `list_filter` au niveau de la classe `ModelAdmin` :
|
||||
|
||||
==== Verticaux
|
||||
```python
|
||||
[...]
|
||||
|
||||
==== Temporels
|
||||
@admin.register(Item)
|
||||
class ItemAdmin(admin.ModelAdmin):
|
||||
list_display = ("__str__", "wishlist_name")
|
||||
list_filter = ("wishlist__name",) <1>
|
||||
|
||||
==== Conclusions
|
||||
[...]
|
||||
```
|
||||
<1> `list_filter` est un tuple, qui prend autant de valeurs que nous souhaitons définir de filtres différents. Nous utilisons ici un _lookup_ de type `__` pour définir précisément sur quel champ nous souhaitons pouvoir appliquer un filtre.
|
||||
|
||||
image::django/admin/django-list-filter.png[align="center"]
|
||||
|
||||
===== Temporels
|
||||
|
||||
Les filtres temporels ajoutent la possibilité de naviguer chronologiquement parmi des données.
|
||||
Il sera nécessaire de leur donner des informations horodatées, comme par exemple une date de création ou de modification :
|
||||
|
||||
```python
|
||||
[...]
|
||||
|
||||
@admin.register(Item)
|
||||
class ItemAdmin(admin.ModelAdmin):
|
||||
list_display = ("__str__", "wishlist_name")
|
||||
list_filter = ("wishlist__name",)
|
||||
date_hierarchy = "modified_at" <1>
|
||||
[...]
|
||||
```
|
||||
<1> Cette propriété-ci prend comme valeur le nom d'une propriété typé comme étant une date ou un moment. Il ne s'agit donc pas d'un tuple ou d'une liste !
|
||||
|
||||
image::django/admin/date-hierarchy.png[align="center"]
|
||||
|
||||
===== Filtres horizontaux
|
||||
|
||||
Les filtres horizontaux sont représentés par des clés de type `ManyToMany`.
|
||||
Le prérequis sera donc de disposer d'un champ de ce type-là.
|
||||
|
||||
===== Filtres verticaux
|
||||
|
||||
Idem pour les filtres verticaux, qui se basent également des champs de type `ManyToMany`, mais qui représenteront l'information verticalement.
|
||||
|
||||
|
||||
===== Conclusions
|
||||
|
||||
|
||||
|
||||
|
||||
==== Affichage des détails d'un élément
|
||||
|
||||
*... montrer le regroup_by et les collapse.*
|
||||
|
||||
|
||||
=== Permissions
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 86 KiB |
Binary file not shown.
After Width: | Height: | Size: 111 KiB |
Binary file not shown.
After Width: | Height: | Size: 53 KiB |
Binary file not shown.
After Width: | Height: | Size: 79 KiB |
Binary file not shown.
After Width: | Height: | Size: 60 KiB |
|
@ -37,6 +37,7 @@ INSTALLED_APPS = [
|
|||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
"wish",
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from .models import Item, WishList
|
||||
|
||||
|
||||
admin.site.site_header = "Gwift Secret Area"
|
||||
|
||||
|
||||
@admin.register(Item)
|
||||
class ItemAdmin(admin.ModelAdmin):
|
||||
list_display = ("__str__", "wishlist")
|
||||
list_filter = ["wishlist__name"]
|
||||
date_hierarchy = "modified_at"
|
||||
|
||||
|
||||
@admin.register(WishList)
|
||||
class WishListAdmin(admin.ModelAdmin):
|
||||
pass
|
|
@ -0,0 +1,6 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class WishConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'wish'
|
|
@ -0,0 +1,30 @@
|
|||
# Generated by Django 5.0.1 on 2024-02-01 19:26
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='WishList',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Item',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('wishlist', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='wish.wishlist')),
|
||||
],
|
||||
),
|
||||
]
|
|
@ -0,0 +1,25 @@
|
|||
# Generated by Django 5.0.1 on 2024-02-01 20:30
|
||||
|
||||
import django.utils.timezone
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('wish', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='item',
|
||||
name='created_at',
|
||||
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='item',
|
||||
name='modified_at',
|
||||
field=models.DateTimeField(auto_now=True),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,15 @@
|
|||
from django.db import models
|
||||
|
||||
|
||||
class WishList(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class Item(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
wishlist = models.ForeignKey(WishList, on_delete=models.CASCADE)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
modified_at = models.DateTimeField(auto_now=True)
|
|
@ -0,0 +1,3 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
|
@ -0,0 +1,3 @@
|
|||
from django.shortcuts import render
|
||||
|
||||
# Create your views here.
|
Loading…
Reference in New Issue