diff --git a/db/migrations/0003_remove_ticket_unique_ticket_for_session_and_more.py b/db/migrations/0003_remove_ticket_unique_ticket_for_session_and_more.py new file mode 100644 index 000000000..ad4451c90 --- /dev/null +++ b/db/migrations/0003_remove_ticket_unique_ticket_for_session_and_more.py @@ -0,0 +1,21 @@ +# Generated by Django 4.0.2 on 2024-09-04 14:04 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('db', '0002_user_order_alter_movie_actors_alter_movie_genres_and_more'), + ] + + operations = [ + migrations.RemoveConstraint( + model_name='ticket', + name='unique_ticket_for_session', + ), + migrations.AddConstraint( + model_name='ticket', + constraint=models.UniqueConstraint(fields=('movie_session', 'row', 'seat'), name='unique_row_and_seat_for_movie_session'), + ), + ] diff --git a/db/models.py b/db/models.py index 8bf9999dd..4c77f1a5f 100644 --- a/db/models.py +++ b/db/models.py @@ -1,8 +1,7 @@ -import datetime - +from django.contrib.auth.models import AbstractUser from django.core.exceptions import ValidationError from django.db import models -from django.contrib.auth.models import AbstractUser +from django.conf import settings class Genre(models.Model): @@ -61,24 +60,28 @@ class User(AbstractUser): class Order(models.Model): - created_at = models.DateTimeField() + created_at = models.DateTimeField(auto_now_add=True) user = models.ForeignKey( - User, + settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="orders" ) - def __str__(self) -> str: - return f"{self.created_at}" - class Meta: ordering = ["-created_at"] - def save(self, **kwargs) -> None: + @property + def created_at_str(self, **kwargs) -> str: if not self.created_at: - self.created_at = datetime.datetime.now() + return "unknown_time" - super(Order, self).save(**kwargs) + return self.created_at.strftime("%Y-%m-%d %H:%M:%S") + + def __repr__(self) -> str: + return f"<{self.__class__.__name__}: {self.created_at_str}>" + + def __str__(self) -> str: + return f"{self.created_at}" class Ticket(models.Model): @@ -95,6 +98,14 @@ class Ticket(models.Model): row = models.IntegerField() seat = models.IntegerField() + class Meta: + constraints = [ + models.UniqueConstraint( + fields=["movie_session", "row", "seat"], + name="unique_row_and_seat_for_movie_session" + ) + ] + def __str__(self) -> str: return (f"{self.movie_session}" f" (row: {self.row}, seat: {self.seat})") @@ -103,6 +114,12 @@ def clean(self) -> None: cinema_hall = self.movie_session.cinema_hall errors = {} + if self.row < 0: + errors["row"] = ["row should be bigger than 0"] + + if self.seat < 0: + errors["seat"] = ["seat should be bigger than 0"] + if self.row > cinema_hall.rows: errors["row"] = [f"row number must be in available range:" f" (1, rows): (1, {cinema_hall.rows})"] @@ -118,11 +135,3 @@ def clean(self) -> None: def save(self, *args, **kwargs) -> None: self.full_clean() super().save(*args, **kwargs) - - class Meta: - constraints = [ - models.UniqueConstraint( - fields=["movie_session", "row", "seat"], - name="unique_ticket_for_session" - ) - ] diff --git a/services/movie.py b/services/movie.py index a96f8b352..abd46b141 100644 --- a/services/movie.py +++ b/services/movie.py @@ -5,9 +5,9 @@ def get_movies( - genres_ids: list[int] = None, - actors_ids: list[int] = None, - title: str = None + genres_ids: list[int] | None = None, + actors_ids: list[int] | None = None, + title: str | None = None ) -> QuerySet: queryset = Movie.objects.all() @@ -30,8 +30,8 @@ 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, + genres_ids: list | None = None, + actors_ids: list | None = None, ) -> Movie: with transaction.atomic(): movie = Movie.objects.create( diff --git a/services/movie_session.py b/services/movie_session.py index 748d4374c..7700b79ac 100644 --- a/services/movie_session.py +++ b/services/movie_session.py @@ -1,6 +1,6 @@ -from django.db.models import QuerySet +from django.db.models import QuerySet, F -from db.models import MovieSession, Ticket +from db.models import MovieSession def create_movie_session( @@ -13,7 +13,7 @@ def create_movie_session( ) -def get_movies_sessions(session_date: str = None) -> QuerySet: +def get_movies_sessions(session_date: str | None = None) -> QuerySet: queryset = MovieSession.objects.all() if session_date: queryset = queryset.filter(show_time__date=session_date) @@ -21,16 +21,16 @@ def get_movies_sessions(session_date: str = None) -> QuerySet: def get_movie_session_by_id(movie_session_id: int) -> MovieSession: - return MovieSession.objects.get(id=movie_session_id) + return MovieSession.objects.get(pk=movie_session_id) def update_movie_session( session_id: int, - show_time: str = None, - movie_id: int = None, - cinema_hall_id: int = None, + show_time: str | None = None, + movie_id: int | None = None, + cinema_hall_id: int | None = None, ) -> None: - movie_session = MovieSession.objects.get(id=session_id) + movie_session = MovieSession.objects.get(pk=session_id) if show_time: movie_session.show_time = show_time if movie_id: @@ -41,9 +41,13 @@ def update_movie_session( def delete_movie_session_by_id(session_id: int) -> None: - MovieSession.objects.get(id=session_id).delete() + MovieSession.objects.get(pk=session_id).delete() 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] + return list( + MovieSession.objects + .filter(pk=movie_session_id) + .prefetch_related("tickets") + .values(row=F("tickets__row"), seat=F("tickets__seat")) + ) diff --git a/services/order.py b/services/order.py index 2bc718858..b2191c90c 100644 --- a/services/order.py +++ b/services/order.py @@ -1,4 +1,5 @@ -from db.models import User +from django.contrib.auth import get_user_model + from django.db import transaction from django.db.models import QuerySet @@ -8,14 +9,17 @@ def create_order( tickets: list[dict], username: str, - date: str = None + date: str | None = None ) -> Order: with transaction.atomic(): - user = User.objects.get(username=username) - order = Order.objects.create(user=user, created_at=date) + user = get_user_model().objects.get(username=username) + order = Order.objects.create(user=user) + if date: + order.created_at = date + order.save() for ticket in tickets: - MovieSession.objects.get(id=ticket["movie_session"]) + MovieSession.objects.get(pk=ticket["movie_session"]) Ticket.objects.create( movie_session_id=ticket["movie_session"], order=order, @@ -26,8 +30,8 @@ def create_order( return order -def get_orders(username: str = None) -> QuerySet: +def get_orders(username: str | None = None) -> QuerySet: + filters = {} if username: - user = User.objects.get(username=username) - return Order.objects.filter(user=user) - return Order.objects.all() + filters["user__username"] = username + return Order.objects.filter(**filters) diff --git a/services/user.py b/services/user.py index a5617cf78..48c4f3989 100644 --- a/services/user.py +++ b/services/user.py @@ -1,14 +1,19 @@ +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, + email: str | None = None, + first_name: str | None = None, last_name: str = None ) -> User: - user = User.objects.create_user(username=username, password=password) + user = get_user_model().objects.create_user( + username=username, + password=password + ) if email: user.email = email @@ -22,16 +27,16 @@ def create_user( def get_user(user_id: int) -> User: - return User.objects.get(id=user_id) + 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 + username: str | None = None, + password: str | None = None, + email: str | None = None, + first_name: str | None = None, + last_name: str | None = None ) -> User: user = get_user(user_id)