From ea704cfdbcb17759d7ed46b0b0cd653bebd3edf8 Mon Sep 17 00:00:00 2001 From: Vladyslav Bondarenko <128479458+VladyslavBon@users.noreply.github.com> Date: Wed, 4 Dec 2024 15:11:51 +0200 Subject: [PATCH] Solution --- ...ovie_actors_alter_movie_genres_and_more.py | 41 +++++++++ cinema/models.py | 24 ++++-- cinema/serializers.py | 85 ++++++++++++++++++- cinema/urls.py | 29 ++++++- cinema/views.py | 70 ++++++++++++++- cinema_service/urls.py | 3 +- 6 files changed, 243 insertions(+), 9 deletions(-) create mode 100644 cinema/migrations/0005_alter_movie_actors_alter_movie_genres_and_more.py diff --git a/cinema/migrations/0005_alter_movie_actors_alter_movie_genres_and_more.py b/cinema/migrations/0005_alter_movie_actors_alter_movie_genres_and_more.py new file mode 100644 index 00000000..8f355c9f --- /dev/null +++ b/cinema/migrations/0005_alter_movie_actors_alter_movie_genres_and_more.py @@ -0,0 +1,41 @@ +# Generated by Django 4.0.4 on 2024-12-04 12:24 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('cinema', '0004_alter_genre_name'), + ] + + operations = [ + migrations.AlterField( + model_name='movie', + name='actors', + field=models.ManyToManyField(related_name='movies', to='cinema.actor'), + ), + migrations.AlterField( + model_name='movie', + name='genres', + field=models.ManyToManyField(related_name='movies', to='cinema.genre'), + ), + migrations.AlterField( + model_name='moviesession', + name='cinema_hall', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='movie_sessions', to='cinema.cinemahall'), + ), + migrations.AlterField( + model_name='moviesession', + name='movie', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='movie_sessions', to='cinema.movie'), + ), + migrations.AlterField( + model_name='order', + name='user', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='orders', to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/cinema/models.py b/cinema/models.py index c42d2a3d..69a50ccb 100644 --- a/cinema/models.py +++ b/cinema/models.py @@ -27,6 +27,10 @@ class Actor(models.Model): first_name = models.CharField(max_length=255) last_name = models.CharField(max_length=255) + @property + def full_name(self): + return f"{self.first_name} {self.last_name}" + def __str__(self): return self.first_name + " " + self.last_name @@ -35,8 +39,8 @@ class Movie(models.Model): title = models.CharField(max_length=255) description = models.TextField() duration = models.IntegerField() - genres = models.ManyToManyField(Genre) - actors = models.ManyToManyField(Actor) + genres = models.ManyToManyField(Genre, related_name="movies") + actors = models.ManyToManyField(Actor, related_name="movies") class Meta: ordering = ["title"] @@ -47,8 +51,16 @@ def __str__(self): class MovieSession(models.Model): show_time = models.DateTimeField() - movie = models.ForeignKey(Movie, on_delete=models.CASCADE) - cinema_hall = models.ForeignKey(CinemaHall, on_delete=models.CASCADE) + movie = models.ForeignKey( + Movie, + related_name="movie_sessions", + on_delete=models.CASCADE + ) + cinema_hall = models.ForeignKey( + CinemaHall, + related_name="movie_sessions", + on_delete=models.CASCADE + ) class Meta: ordering = ["-show_time"] @@ -60,7 +72,9 @@ def __str__(self): class Order(models.Model): created_at = models.DateTimeField(auto_now_add=True) user = models.ForeignKey( - settings.AUTH_USER_MODEL, on_delete=models.CASCADE + settings.AUTH_USER_MODEL, + related_name="orders", + on_delete=models.CASCADE ) def __str__(self): diff --git a/cinema/serializers.py b/cinema/serializers.py index 612ca7e2..be3d0426 100644 --- a/cinema/serializers.py +++ b/cinema/serializers.py @@ -1 +1,84 @@ -# write serializers here +from rest_framework import serializers + +from cinema.models import ( + Genre, + Actor, + CinemaHall, + Movie, + MovieSession +) + + +class GenreSerializer(serializers.ModelSerializer): + class Meta: + model = Genre + fields = ["id", "name"] + + +class ActorSerializer(serializers.ModelSerializer): + class Meta: + model = Actor + fields = ["id", "first_name", "last_name", "full_name"] + + +class CinemaHallSerializer(serializers.ModelSerializer): + class Meta: + model = CinemaHall + fields = ["id", "name", "rows", "seats_in_row", "capacity"] + + +class MovieSerializer(serializers.ModelSerializer): + class Meta: + model = Movie + fields = ["id", "title", "description", "duration", "genres", "actors"] + + +class MovieListSerializer(MovieSerializer): + genres = serializers.SlugRelatedField( + many=True, + read_only=True, + slug_field="name" + ) + actors = serializers.SlugRelatedField( + many=True, + read_only=True, + slug_field="full_name" + ) + + +class MovieRetrieveSerializer(MovieSerializer): + genres = GenreSerializer(many=True, read_only=True) + actors = ActorSerializer(many=True, read_only=True) + + +class MovieSessionSerializer(serializers.ModelSerializer): + class Meta: + model = MovieSession + fields = ["id", "show_time", "movie", "cinema_hall"] + + +class MovieSessionListSerializer(serializers.ModelSerializer): + movie_title = serializers.CharField(source="movie.title", read_only=True) + cinema_hall_name = serializers.CharField( + source="cinema_hall.name", + read_only=True + ) + cinema_hall_capacity = serializers.IntegerField( + source="cinema_hall.capacity", + read_only=True + ) + + class Meta: + model = MovieSession + fields = [ + "id", + "show_time", + "movie_title", + "cinema_hall_name", + "cinema_hall_capacity" + ] + + +class MovieSessionRetrieveSerializer(MovieSessionSerializer): + movie = MovieListSerializer(read_only=True) + cinema_hall = CinemaHallSerializer(read_only=True) diff --git a/cinema/urls.py b/cinema/urls.py index 420f8e8c..1ccb3909 100644 --- a/cinema/urls.py +++ b/cinema/urls.py @@ -1 +1,28 @@ -# write urls here +from django.urls import path, include +from rest_framework.routers import DefaultRouter + +from cinema.views import ( + GenreViewSet, + ActorViewSet, + MovieViewSet, + CinemaHallViewSet, + MovieSessionViewSet, +) + + +router = DefaultRouter() +router.register("genres", GenreViewSet, basename="genres") +router.register("actors", ActorViewSet, basename="actors") +router.register("cinema_halls", CinemaHallViewSet, basename="cinema_halls") +router.register("movies", MovieViewSet, basename="movies") +router.register( + "movie_sessions", + MovieSessionViewSet, + basename="movie_sessions" +) + +urlpatterns = [ + path("", include(router.urls)), +] + +app_name = "cinema" diff --git a/cinema/views.py b/cinema/views.py index ae87bfde..9ae96d6d 100644 --- a/cinema/views.py +++ b/cinema/views.py @@ -1 +1,69 @@ -# write views here +from rest_framework import viewsets + +from cinema.models import ( + Genre, + Actor, + CinemaHall, + Movie, + MovieSession +) +from cinema.serializers import ( + GenreSerializer, + ActorSerializer, + CinemaHallSerializer, + MovieSerializer, + MovieSessionSerializer, + MovieListSerializer, + MovieRetrieveSerializer, + MovieSessionRetrieveSerializer, + MovieSessionListSerializer +) + + +class GenreViewSet(viewsets.ModelViewSet): + queryset = Genre.objects.all() + serializer_class = GenreSerializer + + +class ActorViewSet(viewsets.ModelViewSet): + queryset = Actor.objects.all() + serializer_class = ActorSerializer + + +class CinemaHallViewSet(viewsets.ModelViewSet): + queryset = CinemaHall.objects.all() + serializer_class = CinemaHallSerializer + + +class MovieViewSet(viewsets.ModelViewSet): + queryset = Movie.objects.all() + + def get_queryset(self): + queryset = self.queryset + if self.action in ("list", "retrieve"): + queryset = queryset.prefetch_related("genres", "actors") + return queryset + + def get_serializer_class(self): + if self.action == "list": + return MovieListSerializer + elif self.action == "retrieve": + return MovieRetrieveSerializer + return MovieSerializer + + +class MovieSessionViewSet(viewsets.ModelViewSet): + queryset = MovieSession.objects.all() + + def get_queryset(self): + queryset = self.queryset + if self.action in ("list", "retrieve"): + queryset = queryset.select_related("movie", "cinema_hall") + return queryset + + def get_serializer_class(self): + if self.action == "list": + return MovieSessionListSerializer + if self.action == "retrieve": + return MovieSessionRetrieveSerializer + return MovieSessionSerializer diff --git a/cinema_service/urls.py b/cinema_service/urls.py index 083932c6..e126f35c 100644 --- a/cinema_service/urls.py +++ b/cinema_service/urls.py @@ -1,6 +1,7 @@ from django.contrib import admin -from django.urls import path +from django.urls import path, include urlpatterns = [ path("admin/", admin.site.urls), + path("api/cinema/", include("cinema.urls", namespace="cinema")) ]