Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Solution #720

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions cinema/migrations/0002_movie_image.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 4.1 on 2024-12-16 18:22

import cinema.models
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('cinema', '0001_initial'),
]

operations = [
migrations.AddField(
model_name='movie',
name='image',
field=models.ImageField(blank=True, null=True, upload_to=cinema.models.movie_image_path),
),
]
13 changes: 13 additions & 0 deletions cinema/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
import pathlib
import uuid

from django.core.exceptions import ValidationError
from django.db import models
from django.conf import settings
from django.utils.text import slugify


def movie_image_path(instance: "Movie", filename: str) -> pathlib.Path:
filename = (
f"{slugify(instance.title)}-{uuid.uuid4()}"
+ pathlib.Path(filename).suffix
)
return pathlib.Path("uploads/movies/") / pathlib.Path(filename)


class CinemaHall(models.Model):
Expand Down Expand Up @@ -41,6 +53,7 @@ class Movie(models.Model):
duration = models.IntegerField()
genres = models.ManyToManyField(Genre)
actors = models.ManyToManyField(Actor)
image = models.ImageField(null=True, upload_to=movie_image_path)

class Meta:
ordering = ["title"]
Expand Down
54 changes: 50 additions & 4 deletions cinema/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,28 +30,64 @@ class Meta:
fields = ("id", "name", "rows", "seats_in_row", "capacity")


class MovieImageSerializer(serializers.ModelSerializer):
class Meta:
model = Movie
fields = ("id", "image")


class MovieSerializer(serializers.ModelSerializer):
image = MovieImageSerializer(many=False, read_only=True)

class Meta:
model = Movie
fields = ("id", "title", "description", "duration", "genres", "actors")
fields = (
"id",
"title",
"description",
"duration",
"genres",
"actors",
"image",
)


class MovieListSerializer(MovieSerializer):
class MovieListSerializer(serializers.ModelSerializer):
genres = serializers.SlugRelatedField(
many=True, read_only=True, slug_field="name"
)
actors = serializers.SlugRelatedField(
many=True, read_only=True, slug_field="full_name"
)

class Meta:
model = Movie
fields = (
"id",
"title",
"description",
"duration",
"genres",
"actors",
"image",
)


class MovieDetailSerializer(MovieSerializer):
genres = GenreSerializer(many=True, read_only=True)
actors = ActorSerializer(many=True, read_only=True)

class Meta:
model = Movie
fields = ("id", "title", "description", "duration", "genres", "actors")
fields = (
"id",
"title",
"description",
"duration",
"genres",
"actors",
"image",
)


class MovieSessionSerializer(serializers.ModelSerializer):
Expand All @@ -69,6 +105,7 @@ class MovieSessionListSerializer(MovieSessionSerializer):
source="cinema_hall.capacity", read_only=True
)
tickets_available = serializers.IntegerField(read_only=True)
movie_image = MovieImageSerializer(source="movie.image", read_only=True)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The movie_image field in MovieSessionListSerializer is using MovieImageSerializer, which is designed for a Movie instance, not directly for an ImageField. Consider using a simpler field like serializers.ImageField() if you only need the image URL.


class Meta:
model = MovieSession
Expand All @@ -79,6 +116,7 @@ class Meta:
"cinema_hall_name",
"cinema_hall_capacity",
"tickets_available",
"movie_image",
)


Expand Down Expand Up @@ -111,10 +149,18 @@ class MovieSessionDetailSerializer(MovieSessionSerializer):
taken_places = TicketSeatsSerializer(
source="tickets", many=True, read_only=True
)
movie_image = MovieImageSerializer(many=False, read_only=True)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly, in MovieSessionDetailSerializer, the movie_image field is using MovieImageSerializer. Ensure this is intended, as it might expect a nested object rather than just the image field.


class Meta:
model = MovieSession
fields = ("id", "show_time", "movie", "cinema_hall", "taken_places")
fields = (
"id",
"show_time",
"movie",
"cinema_hall",
"taken_places",
"movie_image",
)


class OrderSerializer(serializers.ModelSerializer):
Expand Down
21 changes: 20 additions & 1 deletion cinema/views.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from datetime import datetime

from django.db.models import F, Count
from rest_framework import viewsets, mixins
from rest_framework import viewsets, mixins, status
from rest_framework.authentication import TokenAuthentication
from rest_framework.decorators import action
from rest_framework.pagination import PageNumberPagination
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet, ReadOnlyModelViewSet

from cinema.models import Genre, Actor, CinemaHall, Movie, MovieSession, Order
Expand All @@ -22,6 +24,7 @@
MovieListSerializer,
OrderSerializer,
OrderListSerializer,
MovieImageSerializer,
)


Expand Down Expand Up @@ -101,8 +104,24 @@ def get_serializer_class(self):
if self.action == "retrieve":
return MovieDetailSerializer

if self.action == "upload_image":
return MovieImageSerializer
Comment on lines +107 to +108

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure that MovieImageSerializer is appropriate for handling image uploads. It should be able to process the image data correctly and update the Movie instance.


return MovieSerializer

@action(
methods=["POST"],
detail=True,
url_path="upload-image",
)
def upload_image(self, request, pk=None):
movie = self.get_object()
serializer = self.get_serializer(movie, data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()

return Response(serializer.data, status=status.HTTP_200_OK)


class MovieSessionViewSet(viewsets.ModelViewSet):
queryset = (
Expand Down
4 changes: 4 additions & 0 deletions cinema_service/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@

STATIC_URL = "static/"

MEDIA_ROOT = BASE_DIR / "media"

MEDIA_URL = "/media/"

# Default primary key field type
# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field

Expand Down
4 changes: 3 additions & 1 deletion cinema_service/urls.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import path, include

Expand All @@ -6,4 +8,4 @@
path("api/cinema/", include("cinema.urls", namespace="cinema")),
path("api/user/", include("user.urls", namespace="user")),
path("__debug__/", include("debug_toolbar.urls")),
]
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think, you don't need to add this 3 images to git

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ flake8-quotes==3.3.1
flake8-variables-names==0.0.5
pep8-naming==0.13.2
django-debug-toolbar==3.2.4
djangorestframework==3.13.1
djangorestframework==3.13.1
pillow==11.0.0
38 changes: 36 additions & 2 deletions user/admin.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,39 @@
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.admin import UserAdmin as DjangoUserAdmin
from django.utils.translation import gettext as _
from .models import User

admin.site.register(User, UserAdmin)

@admin.register(User)
class UserAdmin(DjangoUserAdmin):
"""Define admin model for custom User model with no email field."""

fieldsets = (
(None, {"fields": ("email", "password")}),
(_("Personal info"), {"fields": ("first_name", "last_name")}),
(
_("Permissions"),
{
"fields": (
"is_active",
"is_staff",
"is_superuser",
"groups",
"user_permissions",
)
},
),
(_("Important dates"), {"fields": ("last_login", "date_joined")}),
)
add_fieldsets = (
(
None,
{
"classes": ("wide",),
"fields": ("email", "password1", "password2"),
},
),
)
list_display = ("email", "first_name", "last_name", "is_staff")
search_fields = ("email", "first_name", "last_name")
ordering = ("email",)
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Generated by Django 4.1 on 2024-12-16 19:18

from django.db import migrations, models
import user.models


class Migration(migrations.Migration):

dependencies = [
('user', '0001_initial'),
]

operations = [
migrations.AlterModelManagers(
name='user',
managers=[
('objects', user.models.UserManager()),
],
),
migrations.RemoveField(
model_name='user',
name='username',
),
migrations.AlterField(
model_name='user',
name='email',
field=models.EmailField(max_length=254, unique=True, verbose_name='email address'),
),
]
53 changes: 51 additions & 2 deletions user/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,54 @@
from django.contrib.auth.models import AbstractUser
from django.contrib.auth.models import (
AbstractUser,
BaseUserManager as DjangoUserAdmin,
)
from django.utils.translation import gettext as _
from django.db import models


class UserManager(DjangoUserAdmin):
"""Define a model manager for User model with no username field."""

use_in_migrations = True

def _create_user(self, email, password, **extra_fields):
"""Create and save a User with the given email and password."""
if not email:
raise ValueError("The given email must be set")

email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save(using=self._db)

return user

def create_user(self, email, password=None, **extra_fields):
"""Create and save a regular User with the given email and password."""
extra_fields.setdefault("is_staff", False)
extra_fields.setdefault("is_superuser", False)

return self._create_user(email, password, **extra_fields)

def create_superuser(self, email, password, **extra_fields):
"""Create and save a SuperUser with the given email and password."""
extra_fields.setdefault("is_staff", True)
extra_fields.setdefault("is_superuser", True)

if extra_fields.get("is_staff") is not True:
raise ValueError("Superuser must have is_staff=True.")

if extra_fields.get("is_superuser") is not True:
raise ValueError("Superuser must have is_superuser=True.")

return self._create_user(email, password, **extra_fields)


class User(AbstractUser):
pass
username = None
email = models.EmailField(_("email address"), unique=True)

USERNAME_FIELD = "email"
REQUIRED_FIELDS = []

objects = UserManager()
Loading
Loading