From 21d4e9bd80bfa85446f5abb06bf20718f8e84599 Mon Sep 17 00:00:00 2001 From: Andrii Date: Mon, 2 Sep 2024 21:43:59 +0300 Subject: [PATCH] Solution --- db/models.py | 79 ++++++++++++++++++++++++++++++++++++++- services/movie.py | 26 ++++++++----- services/movie_session.py | 10 ++++- services/order.py | 36 ++++++++++++++++++ services/user.py | 53 ++++++++++++++++++++++++++ settings.py | 4 ++ 6 files changed, 196 insertions(+), 12 deletions(-) create mode 100644 services/order.py create mode 100644 services/user.py diff --git a/db/models.py b/db/models.py index 2a3359a63..2c1755224 100644 --- a/db/models.py +++ b/db/models.py @@ -1,4 +1,10 @@ + +from django.contrib.auth.models import AbstractUser +from django.core.exceptions import ValidationError from django.db import models +from django.db.models import UniqueConstraint + +import settings class Genre(models.Model): @@ -17,7 +23,7 @@ def __str__(self) -> str: class Movie(models.Model): - title = models.CharField(max_length=255) + title = models.CharField(max_length=255, db_index=True) description = models.TextField() actors = models.ManyToManyField(to=Actor, related_name="movies") genres = models.ManyToManyField(to=Genre, related_name="movies") @@ -50,3 +56,74 @@ class MovieSession(models.Model): def __str__(self) -> str: return f"{self.movie.title} {str(self.show_time)}" + + +class Order(models.Model): + created_at = models.DateTimeField(auto_now_add=True) + user = models.ForeignKey( + settings.AUTH_USER_MODEL, + on_delete=models.CASCADE + ) + + class Meta: + ordering = ["-created_at"] + + def __str__(self) -> str: + return f"{self.created_at}" + + +class Ticket(models.Model): + movie_session = models.ForeignKey( + MovieSession, + on_delete=models.CASCADE, + related_name="tickets" + ) + order = models.ForeignKey(Order, on_delete=models.CASCADE) + row = models.IntegerField() + seat = models.IntegerField() + + def clean(self) -> None: + if not (1 <= self.row <= self.movie_session.cinema_hall.rows): + raise ValidationError( + { + "row": ( + f"row number must be in available range: " + f"(1, rows): " + f"(1, {self.movie_session.cinema_hall.rows})" + ) + } + ) + + if not (1 <= self.seat <= self.movie_session.cinema_hall.seats_in_row): + raise ValidationError( + { + "seat": ( + f"seat number must be in available range: " + f"(1, seats_in_row): " + f"(1, {self.movie_session.cinema_hall.seats_in_row})" + ) + } + ) + + def save(self, *args, **kwargs) -> None: + self.full_clean() + return super().save(*args, **kwargs) + + class Meta: + constraints = [ + UniqueConstraint( + fields=["row", "seat", "movie_session"], + name="unique_row_seat_movie_session_session" + ), + ] + + def __str__(self) -> str: + return ( + f"{self.movie_session.movie.title} " + f"{self.movie_session.show_time} " + f"(row: {self.row}, seat: {self.seat})" + ) + + +class User(AbstractUser): + pass diff --git a/services/movie.py b/services/movie.py index 4d0f63237..a828ded94 100644 --- a/services/movie.py +++ b/services/movie.py @@ -1,3 +1,4 @@ +from django.db import transaction from django.db.models import QuerySet from db.models import Movie @@ -6,6 +7,7 @@ def get_movies( genres_ids: list[int] = None, actors_ids: list[int] = None, + title: str = None, ) -> QuerySet: queryset = Movie.objects.all() @@ -15,6 +17,9 @@ def get_movies( if actors_ids: queryset = queryset.filter(actors__id__in=actors_ids) + if title: + queryset = queryset.filter(title__icontains=title) + return queryset @@ -28,13 +33,14 @@ def create_movie( genres_ids: list = None, actors_ids: list = None, ) -> Movie: - movie = Movie.objects.create( - title=movie_title, - description=movie_description, - ) - if genres_ids: - movie.genres.set(genres_ids) - if actors_ids: - movie.actors.set(actors_ids) - - return movie + with transaction.atomic(): + movie = Movie.objects.create( + title=movie_title, + description=movie_description, + ) + if genres_ids: + movie.genres.set(genres_ids) + if actors_ids: + movie.actors.set(actors_ids) + + return movie diff --git a/services/movie_session.py b/services/movie_session.py index f326a082e..d0eb0408d 100644 --- a/services/movie_session.py +++ b/services/movie_session.py @@ -1,6 +1,6 @@ from django.db.models import QuerySet -from db.models import MovieSession +from db.models import MovieSession, Ticket def create_movie_session( @@ -24,6 +24,14 @@ def get_movie_session_by_id(movie_session_id: int) -> MovieSession: return MovieSession.objects.get(id=movie_session_id) +def get_taken_seats(movie_session_id: int) -> list[dict]: + return list( + Ticket.objects + .filter(movie_session__id=movie_session_id) + .values("row", "seat") + ) + + def update_movie_session( session_id: int, show_time: str = None, diff --git a/services/order.py b/services/order.py new file mode 100644 index 000000000..10dd990d4 --- /dev/null +++ b/services/order.py @@ -0,0 +1,36 @@ +from django.contrib.auth import get_user_model +from django.db import transaction +from django.db.models import QuerySet + +from db.models import Ticket, Order + + +def create_order(tickets: list[dict], username: str, date: str = None) -> None: + with transaction.atomic(): + user = get_user_model().objects.get(username=username) + order = Order.objects.create(user=user) + + if date: + order.created_at = date + order.save() + + ticket_objects = [ + Ticket( + order=order, + row=ticket["row"], + seat=ticket["seat"], + movie_session_id=ticket["movie_session"] + ) + for ticket in tickets + ] + + Ticket.objects.bulk_create(ticket_objects) + + +def get_orders(username: str = None) -> QuerySet: + queryset = Order.objects.all() + + if username: + queryset = queryset.filter(user__username=username) + + return queryset diff --git a/services/user.py b/services/user.py new file mode 100644 index 000000000..f2cc5c47c --- /dev/null +++ b/services/user.py @@ -0,0 +1,53 @@ +from django.contrib.auth import get_user_model + +from db.models import User + + +def create_user( + username: str, + password: str, + email: str = None, + first_name: str = None, + last_name: str = None +) -> None: + user = get_user_model().objects.create_user( + username=username, + password=password, + ) + + if email: + user.email = email + if first_name: + user.first_name = first_name + if last_name: + user.last_name = last_name + + user.save() + + +def get_user(user_id: int) -> User: + return get_user_model().objects.get(pk=user_id) + + +def update_user( + user_id: int, + username: str = None, + password: str = None, + email: str = None, + first_name: str = None, + last_name: str = None +) -> None: + user = get_user(user_id) + + if username: + user.username = username + if email: + user.email = email + if first_name: + user.first_name = first_name + if last_name: + user.last_name = last_name + if password: + user.set_password(password) + + user.save() diff --git a/settings.py b/settings.py index f25910b30..4656ed778 100644 --- a/settings.py +++ b/settings.py @@ -24,5 +24,9 @@ USE_TZ = False INSTALLED_APPS = [ + "django.contrib.auth", + "django.contrib.contenttypes", "db", ] + +AUTH_USER_MODEL = "db.User"