.. _review_model: .. index:: single: Reviews single: Adminoberfläche single: tabularinline single: models.IntegerChoices single: CASCADE Ein neues Model: Reviews ********************************* Das Review-Model ===================================== Bevor wir mit der Entwicklung der API beginnen, wollen wir noch ein weiteres Model bauen und dafür per FactoryBoy erneut Testdaten generieren lassen. Unsere Events sollen von angemeldeten Nutzern bewertet werden. Dazu benötigen wir ein Review-Model. Auf Views und URLs für das Review-Model verzichten wir in diesem Buch, das sei dem Leser überlassen, das zu implementieren. Uns geht es nur um das Model bzw. die Testdaten. .. image:: /images/uml_class_4.png In dem Diagramm sehen wir eine Klasse ``Tag``, die wir noch gar nicht implementiert haben. Später im Buch, wenn wir ``Many-to-Many`` - Beziehungen angucken, werde ich genauer auf diese Klasse eingehen. Für uns ist sie aktuell an dieser Stelle erstmal uninteressant. Wir öffnen die Datei ``event_manager/events/models.py`` und fügen das Review-Model ein: .. rli:: https://raw.githubusercontent.com/realcaptainsolaris/event_manager_code/main/models/events/6_events.py :language: python :lines: 96-120 Die Klasse ``Review`` beschreibt eine Bewertung eines Users für einen Event. Die Ratings wurden als enum-ähnliche Klasse angelegt, die von ``models.IntegerChoices`` erbt. Auf den User gibt es eine 1:n Beziehung ebenso wie auf das Event. Ein Review kann also einem Event zugeordnet werden, und ein Event hat viele Reviews. Ebenso kann ein User viele Reviews haben, aber ein Review gehört nur einem Autor. Wird der User gelöscht, werden auch die Reviews gelöscht (``on_delete=models.CASCADE``), gleiches geschieht, wenn das Event gelöscht wird. Die gesamte ``event_manager/events/models.py`` sieht nun so aus: .. rli:: https://raw.githubusercontent.com/realcaptainsolaris/event_manager_code/main/models/events/6_events.py :language: python Wir können das Model jetzt migrieren .. code-block:: bash python manage.py makemigrations events python manage.py migrate events Das Review-Model in der Administration verfügbar machen ------------------------------------------------------------- Wir wollen unser Model natürlich auch in der Administrationsoberfläche sehen. Dazu passen wir die Datei ``event_manager/events/admin.py`` an und fügen die Klasse ``ReviewAdmin`` ein: .. code-block:: python @admin.register(Review) class ReviewAdmin(admin.ModelAdmin): list_display = "author", "rating", "event_name" search_fields = ["event__name", "review"] @admin.display(description="Event Name") def event_name(self, obj): """The name of the event of this review.""" return obj.event.name In der Liste der darzustellenden Spalten auf der Review-Übersichtsseite (``list_display``) setzen wir eine Referenz auf ein Feld ``event_name``, welches im Review-Model nicht exisitert. Weiter unten implementieren wir eine Funktion gleichen Namens, die über das Review-Objekt ``obj`` auf den Event-Namen zugreift. Damit können wir nun auch den Event-Namen in der Übersicht angeben. Der ``@admin.display``- Dekorator dient dazu, der Spalte einen schöneren Namen zu geben. Interessant auch die Angabe des Suchfeldes ``search_fields``: Es werden bei der Suche in den Reviews jetzt nur die Event-Namen berücksichtigt, und zwar über den klassischen Field-Lookup ``event__name``. .. image:: /images/review_admin.png Inline Review anlegen ---------------------- Wir sind mit der Admin noch nicht ganz fertig. Es wäre schön, wenn wir auf der Detailseite eines Events auch sehen könnten, ob und welche Reviews angelegt wurden. Das geht mit der Klasse ``admin.tabularInline``. Wir entwickeln eine ``ReviewInlineAdmin``-Klasse, die von ``admin.tabularInline`` erbt und nur dazu da ist, als Inline-Ansicht in einer anderen Admin-Klasse angezeigt zu werden. Wir fügen in ``event_manager/events/admin.py`` ganz oben (vor der ``EventAdmin)`` folgenden Eintrag hinzu: .. code-block:: python class ReviewInlineAdmin(admin.TabularInline): model = Review und inkludieren die Klasse via ``inlines`` in der ``EventAdmin``: .. code-block:: python @admin.register(Event) class EventAdmin(admin.ModelAdmin): inlines = [ReviewInlineAdmin] prepopulated_fields = {"slug": ("name",)} list_display = ( "date", "slug", "author", "name", "category", "category_slug", ) [..] nun können wir auf der Event-Detailseite sehen, ob und welche Reviews für diesen Event eingetragen wurden. Mehr zur ``InlineModelAdmin objects`` in der Django Doku: ``_ Die vollständige ``event_manager/events/admin.py`` sieht jetzt so aus: .. rli:: https://raw.githubusercontent.com/realcaptainsolaris/event_manager_code/main/admin/3_events.py :language: python Testdaten anlegen ---------------------- Nun benötigen wir Testdaten. Dazu nutzen wir wieder ``FactoryBoy`` und öffnen die datei ``event_manager/events/factories.py`` .. code-block:: python class ReviewFactory(factory.django.DjangoModelFactory): class Meta: model = models.Review event = factory.SubFactory(EventFactory) review = factory.Faker("paragraph") und erstellen in ``event_manager/events/management/commands/create_events.py`` die Funktion für das Erstelle von Reviews. Die gesamte Datei ``event_manager/events/management/commands/create_events.py`` sieht nun so aus: .. rli:: https://raw.githubusercontent.com/realcaptainsolaris/event_manager_code/main/commands/2_create_events.py :language: python Wir können in der Admin prüfen, ob die Daten vorhanden sind.