From a7232e2b4f296a3d20304efb8fac76df9a6d1659 Mon Sep 17 00:00:00 2001 From: Roman Zhadan <21gehassig@gmail.com> Date: Tue, 14 Nov 2023 22:46:25 +0200 Subject: [PATCH] 'Solution' --- .gitignore | 1 + db/models.py | 86 ++++++++++++++++++++++++++++++++++++++- services/movie.py | 39 ++++++++++-------- services/movie_session.py | 16 +++++++- services/order.py | 31 ++++++++++++++ services/user.py | 54 ++++++++++++++++++++++++ settings.py | 5 +++ 7 files changed, 214 insertions(+), 18 deletions(-) create mode 100644 services/order.py create mode 100644 services/user.py diff --git a/.gitignore b/.gitignore index baded8703..a2ca380dc 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ venv/ **__pycache__/ *.pyc **db.sqlite3 +db.sqlite3 diff --git a/db/models.py b/db/models.py index 2a3359a63..ea23b8414 100644 --- a/db/models.py +++ b/db/models.py @@ -1,4 +1,11 @@ +from typing import Any + +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 +24,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 +57,80 @@ 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, + related_name="tickets" + ) + row = models.IntegerField() + seat = models.IntegerField() + + class Meta: + constraints = [ + UniqueConstraint( + fields=["row", "seat", "movie_session"], + name="unique_ticket_seat_movie_session") + ] + + def __str__(self) -> str: + return ( + f"{self.movie_session.movie} {self.movie_session.show_time} " + f"(row: {self.row}, seat: {self.seat})" + ) + + 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: (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, + force_insert: bool = False, + force_update: bool = False, + using: Any = None, + update_fields: Any = None + ) -> None: + + self.full_clean() + return super(Ticket, self).save( + force_insert=False, + force_update=False, + using=None, + update_fields=None + ) + + +class User(AbstractUser): + pass diff --git a/services/movie.py b/services/movie.py index 4d0f63237..302d82d53 100644 --- a/services/movie.py +++ b/services/movie.py @@ -1,19 +1,23 @@ from django.db.models import QuerySet +from django.db import transaction from db.models import Movie def get_movies( - genres_ids: list[int] = None, - actors_ids: list[int] = None, + genres_ids: list[int] = None, + actors_ids: list[int] = None, + title: str = None ) -> QuerySet: + queryset = Movie.objects.all() if genres_ids: queryset = queryset.filter(genres__id__in=genres_ids) - if actors_ids: queryset = queryset.filter(actors__id__in=actors_ids) + if title: + queryset = queryset.filter(title__icontains=title) return queryset @@ -23,18 +27,21 @@ def get_movie_by_id(movie_id: int) -> Movie: def create_movie( - movie_title: str, - movie_description: str, - genres_ids: list = None, - actors_ids: list = None, + movie_title: str, + movie_description: str, + 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..758ab8ca5 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( @@ -20,6 +20,17 @@ def get_movies_sessions(session_date: str = None) -> QuerySet: return queryset +def get_taken_seats(movie_session_id: int) -> list[dict]: + tickets = Ticket.objects.filter(movie_session_id=movie_session_id) + return [ + { + "row": ticket.row, + "seat": ticket.seat + } + for ticket in tickets + ] + + def get_movie_session_by_id(movie_session_id: int) -> MovieSession: return MovieSession.objects.get(id=movie_session_id) @@ -30,13 +41,16 @@ def update_movie_session( movie_id: int = None, cinema_hall_id: int = None, ) -> None: + movie_session = MovieSession.objects.get(id=session_id) + if show_time: movie_session.show_time = show_time if movie_id: movie_session.movie_id = movie_id if cinema_hall_id: movie_session.cinema_hall_id = cinema_hall_id + movie_session.save() diff --git a/services/order.py b/services/order.py new file mode 100644 index 000000000..be014e96e --- /dev/null +++ b/services/order.py @@ -0,0 +1,31 @@ +from db.models import Ticket, Order, User, MovieSession +from django.db import transaction +from django.db.models.query import QuerySet + + +def create_order(tickets: list[dict], + username: str, + date: str = None) -> None: + with transaction.atomic(): + customer_user = User.objects.get(username=username) + user_order = Order.objects.create(user=customer_user) + + if date: + user_order.created_at = date + user_order.save() + + for ticket in tickets: + Ticket.objects.create( + movie_session=MovieSession.objects.get( + id=ticket["movie_session"] + ), + order=user_order, + row=ticket["row"], + seat=ticket["seat"] + ) + + +def get_orders(username: str = None) -> QuerySet: + if username: + return Order.objects.filter(user__username=username) + return Order.objects.all() diff --git a/services/user.py b/services/user.py new file mode 100644 index 000000000..2b5b95fba --- /dev/null +++ b/services/user.py @@ -0,0 +1,54 @@ +from db.models import User +from django.contrib.auth import get_user_model + + +def create_user( + username: str, + password: str, + email: str = None, + first_name: str = None, + last_name: str = None +) -> None: + + new_user = get_user_model().objects.create_user( + username=username, + password=password, + ) + + if email: + new_user.email = email + if first_name: + new_user.first_name = first_name + if last_name: + new_user.last_name = last_name + + new_user.save() + + +def get_user(user_id: int) -> User: + return get_user_model().objects.get(id=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: + + currently_user = get_user_model().objects.get(id=user_id) + + if username: + currently_user.username = username + if password: + currently_user.set_password(password) + if email: + currently_user.email = email + if first_name: + currently_user.first_name = first_name + if last_name: + currently_user.last_name = last_name + + currently_user.save() diff --git a/settings.py b/settings.py index f25910b30..e368fcd0a 100644 --- a/settings.py +++ b/settings.py @@ -25,4 +25,9 @@ INSTALLED_APPS = [ "db", + "django.contrib.auth", + "django.contrib.contenttypes", ] + + +AUTH_USER_MODEL = "db.User"