Skip to content

Commit

Permalink
solution
Browse files Browse the repository at this point in the history
  • Loading branch information
xtsvi committed Nov 16, 2024
1 parent befd89e commit 5164c0e
Show file tree
Hide file tree
Showing 9 changed files with 164 additions and 23 deletions.
3 changes: 2 additions & 1 deletion cinema/migrations/0001_initial.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ class Migration(migrations.Migration):
(
"movie",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="cinema.movie"
on_delete=django.db.models.deletion.CASCADE,
to="cinema.movie",
),
),
],
Expand Down
6 changes: 4 additions & 2 deletions cinema/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ def validate_ticket(row, seat, cinema_hall, error_to_raise):
if not (1 <= ticket_attr_value <= count_attrs):
raise error_to_raise(
{
ticket_attr_name: f"{ticket_attr_name} number must be in available range: "
ticket_attr_name: f"{ticket_attr_name} number "
f"must be in available range: "
f"(1, {cinema_hall_attr_name}): "
f"(1, {count_attrs})"
}
Expand Down Expand Up @@ -122,7 +123,8 @@ def save(

def __str__(self):
return (
f"{str(self.movie_session)} (row: {self.row}, seat: {self.seat})"
f"{str(self.movie_session)} "
f"(row: {self.row}, seat: {self.seat})"
)

class Meta:
Expand Down
15 changes: 15 additions & 0 deletions cinema/permissions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from rest_framework.permissions import BasePermission, SAFE_METHODS


class IsAdminOrIfAuthenticatedReadOnly(BasePermission):
"""
The request is authenticated as an admin - read/write,
if as user - a read-only.
"""

def has_permission(self, request, view):
return bool(
request.method in SAFE_METHODS
and request.user
and request.user.is_authenticated
) or (request.user and request.user.is_staff)
78 changes: 62 additions & 16 deletions cinema/views.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
from datetime import datetime

from django.db.models import F, Count
from rest_framework import viewsets
from rest_framework import viewsets, mixins
from rest_framework.authentication import TokenAuthentication
from rest_framework.pagination import PageNumberPagination

from cinema.models import Genre, Actor, CinemaHall, Movie, MovieSession, Order

from rest_framework.permissions import IsAuthenticated
from rest_framework.viewsets import GenericViewSet

from cinema.models import (
Genre,
Actor,
CinemaHall,
Movie,
MovieSession,
Order,
)
from cinema.permissions import IsAdminOrIfAuthenticatedReadOnly
from cinema.serializers import (
GenreSerializer,
ActorSerializer,
Expand All @@ -21,24 +31,50 @@
)


class GenreViewSet(viewsets.ModelViewSet):
class GenreViewSet(
mixins.CreateModelMixin,
mixins.ListModelMixin,
GenericViewSet
):
queryset = Genre.objects.all()
serializer_class = GenreSerializer
authentication_classes = (TokenAuthentication,)
permission_classes = (IsAdminOrIfAuthenticatedReadOnly,)


class ActorViewSet(viewsets.ModelViewSet):
class ActorViewSet(
mixins.CreateModelMixin,
mixins.ListModelMixin,
GenericViewSet
):
queryset = Actor.objects.all()
serializer_class = ActorSerializer
authentication_classes = (TokenAuthentication,)
permission_classes = (IsAdminOrIfAuthenticatedReadOnly,)


class CinemaHallViewSet(viewsets.ModelViewSet):
class CinemaHallViewSet(
mixins.CreateModelMixin,
mixins.ListModelMixin,
GenericViewSet
):
queryset = CinemaHall.objects.all()
serializer_class = CinemaHallSerializer
authentication_classes = (TokenAuthentication,)
permission_classes = (IsAdminOrIfAuthenticatedReadOnly,)


class MovieViewSet(viewsets.ModelViewSet):
queryset = Movie.objects.all().prefetch_related("genres", "actors")
class MovieViewSet(
mixins.CreateModelMixin,
mixins.ListModelMixin,
mixins.RetrieveModelMixin,
GenericViewSet
):
queryset = Movie.objects.prefetch_related("genres", "actors")

serializer_class = MovieSerializer
authentication_classes = (TokenAuthentication,)
permission_classes = (IsAdminOrIfAuthenticatedReadOnly,)

@staticmethod
def _params_to_ints(qs):
Expand All @@ -63,7 +99,6 @@ def get_queryset(self):
if actors:
actors_ids = self._params_to_ints(actors)
queryset = queryset.filter(actors__id__in=actors_ids)

return queryset.distinct()

def get_serializer_class(self):
Expand All @@ -81,12 +116,15 @@ class MovieSessionViewSet(viewsets.ModelViewSet):
MovieSession.objects.all()
.select_related("movie", "cinema_hall")
.annotate(
tickets_available=F("cinema_hall__rows")
* F("cinema_hall__seats_in_row")
- Count("tickets")
tickets_available=(F("cinema_hall__rows")
* F("cinema_hall__seats_in_row")
- Count("tickets")
)
)
)
serializer_class = MovieSessionSerializer
authentication_classes = (TokenAuthentication,)
permission_classes = (IsAdminOrIfAuthenticatedReadOnly,)

def get_queryset(self):
date = self.request.query_params.get("date")
Expand Down Expand Up @@ -118,20 +156,28 @@ class OrderPagination(PageNumberPagination):
max_page_size = 100


class OrderViewSet(viewsets.ModelViewSet):
queryset = Order.objects.all().prefetch_related(
class OrderViewSet(
mixins.CreateModelMixin,
mixins.ListModelMixin,
GenericViewSet
):
queryset = Order.objects.prefetch_related(
"tickets__movie_session__movie", "tickets__movie_session__cinema_hall"
)
serializer_class = OrderSerializer
pagination_class = OrderPagination
authentication_classes = (TokenAuthentication,)
permission_classes = (IsAuthenticated,)
lookup_field = "id"

def get_queryset(self):
return Order.objects.filter(user=self.request.user)

def get_serializer_class(self):
if self.action == "list":
return OrderListSerializer

elif self.action == "retrieve":
return OrderSerializer
return OrderSerializer

def perform_create(self, serializer):
Expand Down
2 changes: 1 addition & 1 deletion cinema_service/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@

USE_I18N = True

USE_TZ = False
USE_TZ = True


# Static files (CSS, JavaScript, Images)
Expand Down
1 change: 1 addition & 0 deletions cinema_service/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
urlpatterns = [
path("admin/", admin.site.urls),
path("api/cinema/", include("cinema.urls", namespace="cinema")),
path("api/user/", include("user.urls", namespace="user")),
path("__debug__/", include("debug_toolbar.urls")),
]
39 changes: 38 additions & 1 deletion user/serializers.py
Original file line number Diff line number Diff line change
@@ -1 +1,38 @@
# write your code here
from django.contrib.auth import get_user_model
from rest_framework import serializers


class UserSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
fields = (
"id",
"username",
"email",
"password",
"is_staff"
)
read_only_fields = ("id", "is_staff")
extra_kwargs = {
"password": {
"write_only": True,
"min_length": 5
}
}

def create(self, validated_data):
"""
create user with encrypted password
"""
return get_user_model().objects.create_user(**validated_data)

def update(self, instance, validated_data):
"""
Update User with encrypted password
"""
password = validated_data.pop("password", None)
user = super().update(instance, validated_data)
if password:
user.set_password(password)
user.save()
return user
13 changes: 12 additions & 1 deletion user/urls.py
Original file line number Diff line number Diff line change
@@ -1 +1,12 @@
# write your code here
from django.urls import path

from user.views import CreateUserView, LoginUserView, ManageUserView

app_name = "user"

urlpatterns = [
path("register/", CreateUserView.as_view(), name="create"),
path("login/", LoginUserView.as_view(), name="login"),
path("me/", ManageUserView.as_view(), name="manage")

]
30 changes: 29 additions & 1 deletion user/views.py
Original file line number Diff line number Diff line change
@@ -1 +1,29 @@
# write your code here
from rest_framework import generics
from rest_framework.authentication import TokenAuthentication
from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.permissions import IsAuthenticated
from rest_framework.settings import api_settings

from user.serializers import UserSerializer


class CreateUserView(generics.CreateAPIView):
serializer_class = UserSerializer


class LoginUserView(ObtainAuthToken):
renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES


class ManageUserView(generics.RetrieveUpdateAPIView):
serializer_class = UserSerializer
authentication_classes = (
TokenAuthentication,
)
permission_classes = (IsAuthenticated,)

def get_object(self):
"""
Retrieve and return the authenticated user.
"""
return self.request.user

0 comments on commit 5164c0e

Please sign in to comment.