diff --git a/movie_db/serializers.py b/movie_db/serializers.py index 0f5eca2..077d771 100644 --- a/movie_db/serializers.py +++ b/movie_db/serializers.py @@ -2,10 +2,12 @@ from rest_framework import serializers class MovieSerializer(serializers.Serializer): + actors = serializers.CharField(source="Actors") director = serializers.CharField(source="Director") genre = serializers.CharField(source="Genre") imdb_id = serializers.CharField(source="imdbID") - imdb_rating = serializers.CharField(source="imdbRating") + critic_scores = serializers.CharField(source="Ratings") + mpaa_rating = serializers.CharField(source="Rated") media_type = serializers.CharField(source="Type") plot = serializers.CharField(source="Plot") poster = serializers.CharField(source="Poster") diff --git a/movie_manager/admin.py b/movie_manager/admin.py index 8c38f3f..b199e47 100644 --- a/movie_manager/admin.py +++ b/movie_manager/admin.py @@ -1,3 +1,24 @@ from django.contrib import admin +from movie_manager.models import Movie, MovieList, Schedule, Showing + + # Register your models here. +@admin.register(Movie) +class MovieAdmin(admin.ModelAdmin): + pass + + +@admin.register(MovieList) +class MovieListAdmin(admin.ModelAdmin): + pass + + +@admin.register(Schedule) +class ScheduleAdmin(admin.ModelAdmin): + pass + + +@admin.register(Showing) +class ShowingAdmin(admin.ModelAdmin): + pass diff --git a/movie_manager/migrations/0001_initial.py b/movie_manager/migrations/0001_initial.py index 8b7d822..19195fa 100644 --- a/movie_manager/migrations/0001_initial.py +++ b/movie_manager/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.1.4 on 2025-03-31 04:04 +# Generated by Django 5.1.4 on 2025-04-21 00:50 import django.db.models.deletion from django.conf import settings @@ -20,18 +20,22 @@ class Migration(migrations.Migration): ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('title', models.CharField(max_length=100)), ('imdb_id', models.CharField(max_length=100)), - ('year', models.IntegerField()), - ('critic_score', models.CharField(max_length=500)), - ('genre', models.CharField(max_length=100)), - ('director', models.CharField(max_length=500)), - ('actors', models.CharField(max_length=500)), - ('plot', models.CharField(max_length=500)), - ('poster', models.CharField(max_length=500)), - ('last_watched', models.DateTimeField()), + ('year', models.IntegerField(blank=True, null=True)), + ('director', models.CharField(blank=True, max_length=500, null=True)), + ('actors', models.TextField(blank=True, null=True)), + ('plot', models.TextField(blank=True, null=True)), + ('genre', models.CharField(blank=True, max_length=100, null=True)), + ('mpaa_rating', models.CharField(blank=True, max_length=20, null=True)), + ('critic_scores', models.TextField(blank=True, null=True)), + ('poster', models.TextField(blank=True, null=True)), ('created_at', models.DateTimeField(auto_now_add=True)), ('updated_at', models.DateTimeField(auto_now=True)), ('deleted_at', models.DateTimeField(blank=True, null=True)), + ('added_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), ], + options={ + 'ordering': ['title'], + }, ), migrations.CreateModel( name='MovieList', @@ -42,7 +46,40 @@ class Migration(migrations.Migration): ('created_at', models.DateTimeField(auto_now_add=True)), ('updated_at', models.DateTimeField(auto_now=True)), ('deleted_at', models.DateTimeField(blank=True, null=True)), + ('movies', models.ManyToManyField(to='movie_manager.movie')), + ('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'ordering': ['name'], + }, + ), + migrations.CreateModel( + name='Schedule', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100)), + ('public', models.BooleanField(default=False)), + ('slug', models.SlugField(default='', max_length=100)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('deleted_at', models.DateTimeField(blank=True, null=True)), ('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ], ), + migrations.CreateModel( + name='Showing', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('public', models.BooleanField(default=False)), + ('showtime', models.DateTimeField()), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('deleted_at', models.DateTimeField(blank=True, null=True)), + ('movie', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='movie_manager.movie')), + ('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'ordering': ['showtime'], + }, + ), ] diff --git a/movie_manager/migrations/0002_alter_movie_options_alter_movielist_options_and_more.py b/movie_manager/migrations/0002_alter_movie_options_alter_movielist_options_and_more.py deleted file mode 100644 index b0f1663..0000000 --- a/movie_manager/migrations/0002_alter_movie_options_alter_movielist_options_and_more.py +++ /dev/null @@ -1,26 +0,0 @@ -# Generated by Django 5.1.4 on 2025-04-07 05:02 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('movie_manager', '0001_initial'), - ] - - operations = [ - migrations.AlterModelOptions( - name='movie', - options={'ordering': ['title']}, - ), - migrations.AlterModelOptions( - name='movielist', - options={'ordering': ['name']}, - ), - migrations.AddField( - model_name='movielist', - name='movies', - field=models.ManyToManyField(to='movie_manager.movie'), - ), - ] diff --git a/movie_manager/migrations/0002_showing_schedule.py b/movie_manager/migrations/0002_showing_schedule.py new file mode 100644 index 0000000..b081684 --- /dev/null +++ b/movie_manager/migrations/0002_showing_schedule.py @@ -0,0 +1,20 @@ +# Generated by Django 5.1.4 on 2025-04-21 01:01 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('movie_manager', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='showing', + name='schedule', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='movie_manager.schedule'), + preserve_default=False, + ), + ] diff --git a/movie_manager/migrations/0003_alter_schedule_options.py b/movie_manager/migrations/0003_alter_schedule_options.py new file mode 100644 index 0000000..08ee78e --- /dev/null +++ b/movie_manager/migrations/0003_alter_schedule_options.py @@ -0,0 +1,17 @@ +# Generated by Django 5.1.4 on 2025-04-21 03:36 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('movie_manager', '0002_showing_schedule'), + ] + + operations = [ + migrations.AlterModelOptions( + name='schedule', + options={'ordering': ['name']}, + ), + ] diff --git a/movie_manager/migrations/0003_movie_added_by.py b/movie_manager/migrations/0003_movie_added_by.py deleted file mode 100644 index 94fee8e..0000000 --- a/movie_manager/migrations/0003_movie_added_by.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 5.1.4 on 2025-04-08 00:18 - -import django.db.models.deletion -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('movie_manager', '0002_alter_movie_options_alter_movielist_options_and_more'), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.AddField( - model_name='movie', - name='added_by', - field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), - preserve_default=False, - ), - ] diff --git a/movie_manager/migrations/0004_alter_movie_last_watched_showing_schedule.py b/movie_manager/migrations/0004_alter_movie_last_watched_showing_schedule.py deleted file mode 100644 index 9895ec9..0000000 --- a/movie_manager/migrations/0004_alter_movie_last_watched_showing_schedule.py +++ /dev/null @@ -1,50 +0,0 @@ -# Generated by Django 5.1.4 on 2025-04-08 03:39 - -import django.db.models.deletion -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('movie_manager', '0003_movie_added_by'), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.AlterField( - model_name='movie', - name='last_watched', - field=models.DateTimeField(blank=True, null=True), - ), - migrations.CreateModel( - name='Showing', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('public', models.BooleanField(default=False)), - ('showtime', models.DateTimeField()), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('updated_at', models.DateTimeField(auto_now=True)), - ('deleted_at', models.DateTimeField(blank=True, null=True)), - ('movie', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='movie_manager.movie')), - ('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), - ], - options={ - 'ordering': ['showtime'], - }, - ), - migrations.CreateModel( - name='Schedule', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=100)), - ('public', models.BooleanField(default=False)), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('updated_at', models.DateTimeField(auto_now=True)), - ('deleted_at', models.DateTimeField(blank=True, null=True)), - ('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), - ('showings', models.ManyToManyField(to='movie_manager.showing')), - ], - ), - ] diff --git a/movie_manager/migrations/0005_showing_slug.py b/movie_manager/migrations/0005_showing_slug.py deleted file mode 100644 index 4d5c0b1..0000000 --- a/movie_manager/migrations/0005_showing_slug.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.1.4 on 2025-04-08 03:45 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('movie_manager', '0004_alter_movie_last_watched_showing_schedule'), - ] - - operations = [ - migrations.AddField( - model_name='showing', - name='slug', - field=models.SlugField(default='', max_length=100), - ), - ] diff --git a/movie_manager/migrations/0006_remove_showing_slug_schedule_slug.py b/movie_manager/migrations/0006_remove_showing_slug_schedule_slug.py deleted file mode 100644 index dfe8b61..0000000 --- a/movie_manager/migrations/0006_remove_showing_slug_schedule_slug.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 5.1.4 on 2025-04-08 04:03 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('movie_manager', '0005_showing_slug'), - ] - - operations = [ - migrations.RemoveField( - model_name='showing', - name='slug', - ), - migrations.AddField( - model_name='schedule', - name='slug', - field=models.SlugField(default='', max_length=100), - ), - ] diff --git a/movie_manager/migrations/0007_alter_movie_critic_score.py b/movie_manager/migrations/0007_alter_movie_critic_score.py deleted file mode 100644 index 2d27d83..0000000 --- a/movie_manager/migrations/0007_alter_movie_critic_score.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.1.4 on 2025-04-12 04:49 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('movie_manager', '0006_remove_showing_slug_schedule_slug'), - ] - - operations = [ - migrations.AlterField( - model_name='movie', - name='critic_score', - field=models.CharField(blank=True, max_length=500, null=True), - ), - ] diff --git a/movie_manager/models.py b/movie_manager/models.py index 1b0c9bf..f401dde 100644 --- a/movie_manager/models.py +++ b/movie_manager/models.py @@ -1,19 +1,21 @@ from django.db import models from django.contrib.auth.models import User +from django.db.models import SET_NULL +import datetime class Movie(models.Model): title = models.CharField(max_length=100) imdb_id = models.CharField(max_length=100) - year = models.IntegerField() - critic_score = models.CharField(max_length=500, null=True, blank=True) - genre = models.CharField(max_length=100) - director = models.CharField(max_length=500) - actors = models.CharField(max_length=500) - plot = models.CharField(max_length=500) - poster = models.CharField(max_length=500) - last_watched = models.DateTimeField(null=True, blank=True) - added_by = models.ForeignKey(User, on_delete=models.CASCADE) + year = models.IntegerField(null=True, blank=True) + director = models.CharField(max_length=500, null=True, blank=True) + actors = models.TextField(null=True, blank=True) + plot = models.TextField(null=True, blank=True) + genre = models.CharField(max_length=100, null=True, blank=True) + mpaa_rating = models.CharField(max_length=20, null=True, blank=True) + critic_scores = models.TextField(null=True, blank=True) + poster = models.TextField(null=True, blank=True) + added_by = models.ForeignKey(User, on_delete=SET_NULL, null=True) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) deleted_at = models.DateTimeField(null=True, blank=True) @@ -45,16 +47,22 @@ class Schedule(models.Model): name = models.CharField(max_length=100) owner = models.ForeignKey(User, on_delete=models.CASCADE) public = models.BooleanField(default=False) - showings = models.ManyToManyField("Showing") slug = models.SlugField(max_length=100, default="") created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) deleted_at = models.DateTimeField(null=True, blank=True) + class Meta: + ordering = ["name"] + + def __str__(self): + return self.name + class Showing(models.Model): movie = models.ForeignKey(Movie, on_delete=models.CASCADE) owner = models.ForeignKey(User, on_delete=models.CASCADE) + schedule = models.ForeignKey(Schedule, on_delete=models.CASCADE) public = models.BooleanField(default=False) showtime = models.DateTimeField() created_at = models.DateTimeField(auto_now_add=True) @@ -63,3 +71,7 @@ class Showing(models.Model): class Meta: ordering = ["showtime"] + + def __str__(self): + showtime = self.showtime.strftime("%Y-%m-%d %H:%M") + return showtime diff --git a/movie_manager/serializers.py b/movie_manager/serializers.py index 2118dc1..75d451c 100644 --- a/movie_manager/serializers.py +++ b/movie_manager/serializers.py @@ -1,3 +1,4 @@ +from django.utils import timezone from gunicorn.config import User from rest_framework import serializers from movie_manager.models import Movie, MovieList, Schedule, Showing @@ -32,12 +33,22 @@ class ShowingSerializer(serializers.ModelSerializer): class Meta: model = Showing - fields = ["public", "showtime", "movie", "owner"] + fields = ["id", "public", "showtime", "movie", "owner"] + + def to_internal_value(self, data): + validated_data = super().to_internal_value(data) + + if "showtime" in validated_data and timezone.is_naive( + validated_data["showtime"] + ): + validated_data["showtime"] = timezone.make_aware(validated_data["showtime"]) + + return validated_data class ScheduleSerializer(serializers.ModelSerializer): name = serializers.CharField(read_only=True) - showings = ShowingSerializer(read_only=True, many=True) + showings = ShowingSerializer(source="showing_set", read_only=True, many=True) class Meta: model = Schedule diff --git a/movie_manager/views.py b/movie_manager/views.py index 1b98766..3dd7d76 100644 --- a/movie_manager/views.py +++ b/movie_manager/views.py @@ -3,6 +3,7 @@ import json from django.http import JsonResponse from django.contrib.auth.models import User +from django.utils.dateparse import parse_datetime from rest_framework import permissions, viewsets from knox.auth import TokenAuthentication from rest_framework.decorators import action, api_view @@ -40,6 +41,14 @@ class MovieListViewset(viewsets.ModelViewSet): serializer_class = MovieListSerializer + def create(self, request, *args, **kwargs): + movie_list = MovieList.objects.create( + name=request.data.get("name"), + owner=request.user, + ) + + return JsonResponse(MovieListSerializer(movie_list).data) + def retrieve(self, request, pk=None, *args, **kwargs): movie_list = MovieList.objects.get(pk=pk) return JsonResponse(MovieListSerializer(movie_list).data) @@ -82,22 +91,24 @@ class MovieListViewset(viewsets.ModelViewSet): new_movie = Movie.objects.create( title=movie["title"], + actors=movie["actors"], year=movie["year"], imdb_id=movie["imdb_id"], poster=movie["poster"], plot=movie["plot"], genre=movie["genre"], - critic_score=movie["imdb_rating"], + critic_scores=movie["critic_scores"], + mpaa_rating=movie["mpaa_rating"], director=movie["director"], added_by_id=request.user.id, ) - movie_list.movies.add(new_movie) + movie_list.movies.add(new_movie) return JsonResponse(MovieListSerializer(movie_list).data) - def remove_movie(self, request, pk=None, movie_id=None, *args, **kwargs): - movie = Movie.objects.get(pk=movie_id) + def remove_movie(self, request, pk=None, imdb_id=None, *args, **kwargs): + movie = Movie.objects.filter(imdb_id=imdb_id).first() movie_list = MovieList.objects.get(pk=pk) movie_list.movies.remove(movie) @@ -117,7 +128,9 @@ class ScheduleViewset(viewsets.ModelViewSet): instance = self.get_object() today = datetime.datetime.now() - upcoming_showings = instance.showings.filter(showtime__gte=today) + upcoming_showings = Showing.objects.filter( + showtime__gte=today, schedule=instance + ) # Create a serialized response serializer = self.get_serializer(instance) @@ -127,7 +140,9 @@ class ScheduleViewset(viewsets.ModelViewSet): data["showings"] = ShowingSerializer(upcoming_showings, many=True).data if request.GET.get("past_showings") == "true": - past_showings = instance.showings.filter(showtime__lt=today) + past_showings = Showing.objects.filter( + showtime__lt=today, schedule=instance + ) # Add both to the response data["past_showings"] = [ @@ -158,14 +173,15 @@ class ShowingViewset(viewsets.ModelViewSet): schedule_id = request.data.get("schedule") schedule = Schedule.objects.get(pk=schedule_id) + showtime_str = request.data.get("showtime") + showtime = parse_datetime(showtime_str) + showing = Showing.objects.create( movie=movie, schedule=schedule, - showtime=request.data.get("showtime"), + showtime=showtime, public=request.data.get("public"), - owner=User.objects.get(pk=request.data.get("owner")), + owner=request.user, ) - schedule.showings.add(showing) - return JsonResponse(ShowingSerializer(showing).data) diff --git a/s User(Base): b/s User(Base): new file mode 100644 index 0000000..f807cbb --- /dev/null +++ b/s User(Base): @@ -0,0 +1,3 @@ + add-schedule-support +* main + movie-search