diff --git a/.gitignore b/.gitignore index fd1f3e48..2fd6d055 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ venv/ .pytest_cache/ **__pycache__/ *.pyc -app/db.sqlite3 \ No newline at end of file +db.sqlite3 +src/ \ No newline at end of file diff --git a/cinema/serializers.py b/cinema/serializers.py index a1a4d7d4..44d8a4af 100644 --- a/cinema/serializers.py +++ b/cinema/serializers.py @@ -1,6 +1,22 @@ from rest_framework import serializers +from cinema.models import (Genre, + Actor, + CinemaHall, + Movie, + MovieSession, + Order, + Ticket + ) -from cinema.models import Genre, Actor, CinemaHall, Movie, MovieSession + +class MovieSessionSerializer(serializers.ModelSerializer): + class Meta: + model = MovieSession + fields = ["id", + "show_time", + "movie_title", + "cinema_hall_name", + "cinema_hall_capacity"] class GenreSerializer(serializers.ModelSerializer): @@ -45,12 +61,6 @@ class Meta: fields = ("id", "title", "description", "duration", "genres", "actors") -class MovieSessionSerializer(serializers.ModelSerializer): - class Meta: - model = MovieSession - fields = ("id", "show_time", "movie", "cinema_hall") - - class MovieSessionListSerializer(MovieSessionSerializer): movie_title = serializers.CharField(source="movie.title", read_only=True) cinema_hall_name = serializers.CharField( @@ -78,3 +88,25 @@ class MovieSessionDetailSerializer(MovieSessionSerializer): class Meta: model = MovieSession fields = ("id", "show_time", "movie", "cinema_hall") + + +class TicketSerializer(serializers.ModelSerializer): + movie_session = MovieSessionSerializer() + + class Meta: + model = Ticket + fields = ["id", "row", "seat", "movie_session"] + + +class OrderSerializer(serializers.ModelSerializer): + tickets = TicketSerializer(many=True) + + class Meta: + model = Order + fields = ["id", "tickets", "created_at"] + + +class CreateOrderSerializer(serializers.ModelSerializer): + class Meta: + model = Order + fields = ["tickets"] diff --git a/cinema/urls.py b/cinema/urls.py index e3586f00..0e4bab55 100644 --- a/cinema/urls.py +++ b/cinema/urls.py @@ -1,21 +1,25 @@ from django.urls import path, include from rest_framework import routers - from cinema.views import ( GenreViewSet, ActorViewSet, CinemaHallViewSet, MovieViewSet, MovieSessionViewSet, + OrderViewSet, ) router = routers.DefaultRouter() router.register("genres", GenreViewSet) router.register("actors", ActorViewSet) router.register("cinema_halls", CinemaHallViewSet) -router.register("movies", MovieViewSet) +router.register("movies", MovieViewSet, basename="movie") router.register("movie_sessions", MovieSessionViewSet) +router.register("orders", OrderViewSet) + -urlpatterns = [path("", include(router.urls))] +urlpatterns = [ + path("", include(router.urls)), +] app_name = "cinema" diff --git a/cinema/views.py b/cinema/views.py index c4ff85e9..68506759 100644 --- a/cinema/views.py +++ b/cinema/views.py @@ -1,6 +1,17 @@ -from rest_framework import viewsets - -from cinema.models import Genre, Actor, CinemaHall, Movie, MovieSession +from rest_framework import viewsets, permissions +from rest_framework.generics import get_object_or_404 +from rest_framework.pagination import PageNumberPagination +from rest_framework.response import Response +from django_filters import rest_framework as filters +from rest_framework.views import APIView +from cinema.models import ( + Genre, + Actor, + CinemaHall, + Movie, + MovieSession, + Order, + Ticket) from cinema.serializers import ( GenreSerializer, @@ -11,22 +22,22 @@ MovieSessionListSerializer, MovieDetailSerializer, MovieSessionDetailSerializer, - MovieListSerializer, + MovieListSerializer, CreateOrderSerializer, OrderSerializer, ) class GenreViewSet(viewsets.ModelViewSet): - queryset = Genre.objects.all() + queryset = Genre.objects.all().order_by("id") serializer_class = GenreSerializer class ActorViewSet(viewsets.ModelViewSet): - queryset = Actor.objects.all() + queryset = Actor.objects.all().order_by("id") serializer_class = ActorSerializer class CinemaHallViewSet(viewsets.ModelViewSet): - queryset = CinemaHall.objects.all() + queryset = CinemaHall.objects.all().order_by("id") serializer_class = CinemaHallSerializer @@ -44,6 +55,74 @@ def get_serializer_class(self): return MovieSerializer +class OrdersPagination(PageNumberPagination): + page_size = 10 + + +class OrderViewSet(viewsets.ModelViewSet): + queryset = Order.objects.all() + permission_classes = [permissions.IsAuthenticated] + pagination_class = OrdersPagination + + def get_queryset(self): + return Order.objects.filter(user=self.request.user) + + def get_serializer_class(self): + if self.request.method == "POST": + return CreateOrderSerializer + return OrderSerializer + + def create(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + self.perform_create(serializer) + return Response(serializer.data, status=201) + + +class MovieSessionFilter(filters.FilterSet): + date = filters.DateFilter(field_name="show_time", lookup_expr="date") + movie = filters.NumberFilter(field_name="movie__id") + + class Meta: + model = MovieSession + fields = ["date", "movie"] + + +class MovieSessionDetailView(APIView): + def get(self, request, pk): + movie_session = get_object_or_404(MovieSession, pk=pk) + taken_places = Ticket.objects.filter( + movie_session=movie_session).values( + "row", + "seat") + + response_data = { + "id": movie_session.id, + "show_time": movie_session.show_time, + "movie": { + "id": movie_session.movie.id, + "title": movie_session.movie.title, + "description": movie_session.movie.description, + "duration": movie_session.movie.duration, + "genres": [genre.name + for genre in + movie_session.movie.genres.all()], + "actors": [actor.name + for actor in + movie_session.movie.actors.all()], + }, + "cinema_hall": { + "id": movie_session.cinema_hall.id, + "name": movie_session.cinema_hall.name, + "rows": movie_session.cinema_hall.rows, + "seats_in_row": movie_session.cinema_hall.seats_in_row, + "capacity": movie_session.cinema_hall.capacity, + }, + "taken_places": list(taken_places), + } + return Response(response_data) + + class MovieSessionViewSet(viewsets.ModelViewSet): queryset = MovieSession.objects.all() serializer_class = MovieSessionSerializer diff --git a/cinema_service/settings.py b/cinema_service/settings.py index a7d6c992..ec7bbf4d 100644 --- a/cinema_service/settings.py +++ b/cinema_service/settings.py @@ -43,6 +43,7 @@ "django.contrib.messages", "django.contrib.staticfiles", "rest_framework", + "django_filters", "debug_toolbar", "cinema", "user", @@ -124,7 +125,7 @@ USE_I18N = True -USE_TZ = False +USE_TZ = True # Static files (CSS, JavaScript, Images) @@ -136,3 +137,9 @@ # https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" + +REST_FRAMEWORK = { + "DEFAULT_PAGINATION_CLASS": + "rest_framework.pagination.PageNumberPagination", + "PAGE_SIZE": 10, +} diff --git a/requirements.txt b/requirements.txt index 56e13554..bef876e8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,16 @@ -django==4.1 +asgiref==3.8.1 +Django==4.2.6 +django-debug-toolbar==3.2.4 +djangorestframework==3.15.2 flake8==5.0.4 flake8-quotes==3.3.1 flake8-variables-names==0.0.5 +mccabe==0.7.0 pep8-naming==0.13.2 -django-debug-toolbar==3.2.4 -djangorestframework==3.13.1 \ No newline at end of file +pycodestyle==2.9.1 +pyflakes==2.5.0 +pytz==2024.2 +six==1.16.0 +sqlparse==0.5.1 +django-filter>=22.1 +djangorestframework-filters \ No newline at end of file diff --git a/src/django-debug-toolbar b/src/django-debug-toolbar new file mode 160000 index 00000000..69b1e276 --- /dev/null +++ b/src/django-debug-toolbar @@ -0,0 +1 @@ +Subproject commit 69b1e276b9815bdf8fad3c3f2476c19cc9ac3bd9