diff --git a/.idea/misc.xml b/.idea/misc.xml
index 3684797..9f60641 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -3,7 +3,7 @@
-
+
-
+
\ No newline at end of file
diff --git a/.idea/movie-night-py.iml b/.idea/movie-night-py.iml
index cdbb1e7..f13645b 100644
--- a/.idea/movie-night-py.iml
+++ b/.idea/movie-night-py.iml
@@ -15,8 +15,9 @@
+
-
+
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
new file mode 100644
index 0000000..9895ec9
--- /dev/null
+++ b/movie_manager/migrations/0004_alter_movie_last_watched_showing_schedule.py
@@ -0,0 +1,50 @@
+# 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
new file mode 100644
index 0000000..4d5c0b1
--- /dev/null
+++ b/movie_manager/migrations/0005_showing_slug.py
@@ -0,0 +1,18 @@
+# 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
new file mode 100644
index 0000000..dfe8b61
--- /dev/null
+++ b/movie_manager/migrations/0006_remove_showing_slug_schedule_slug.py
@@ -0,0 +1,22 @@
+# 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/models.py b/movie_manager/models.py
index 1fcb1ba..171e9e2 100644
--- a/movie_manager/models.py
+++ b/movie_manager/models.py
@@ -1,7 +1,6 @@
from django.db import models
from django.contrib.auth.models import User
-# Create your models here.
class Movie(models.Model):
title = models.CharField(max_length=100)
imdb_id = models.CharField(max_length=100)
@@ -12,7 +11,7 @@ class Movie(models.Model):
actors = models.CharField(max_length=500)
plot = models.CharField(max_length=500)
poster = models.CharField(max_length=500)
- last_watched = models.DateTimeField()
+ last_watched = models.DateTimeField(null=True, blank=True)
added_by = models.ForeignKey(User, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
@@ -39,3 +38,25 @@ class MovieList(models.Model):
def __str__(self):
return self.name
+
+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 Showing(models.Model):
+ movie = models.ForeignKey(Movie, on_delete=models.CASCADE)
+ owner = models.ForeignKey(User, on_delete=models.CASCADE)
+ 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(null=True, blank=True)
+
+ class Meta:
+ ordering = ["showtime"]
diff --git a/movie_manager/serializers.py b/movie_manager/serializers.py
index e79ceff..bebebb0 100644
--- a/movie_manager/serializers.py
+++ b/movie_manager/serializers.py
@@ -1,7 +1,7 @@
-from itertools import count
-
+from gunicorn.config import User
from rest_framework import serializers
-from movie_manager.models import Movie, MovieList
+from movie_manager.models import Movie, MovieList, Schedule, Showing
+
class MovieSerializer(serializers.ModelSerializer):
class Meta:
@@ -20,3 +20,26 @@ class MovieListSerializer(serializers.ModelSerializer):
def get_movie_count(self, obj):
return len(obj.movies.all())
+
+class UserSerializer(serializers.Serializer):
+ class Meta:
+ model = User
+ fields = ["id", "username"]
+
+
+class ShowingSerializer(serializers.ModelSerializer):
+ movie = MovieSerializer(read_only=True)
+
+ class Meta:
+ model = Showing
+ fields = ["public", "showtime", "movie", "owner"]
+
+
+class ScheduleSerializer(serializers.ModelSerializer):
+ name = serializers.CharField(read_only=True)
+ showings = ShowingSerializer(read_only=True, many=True)
+
+ class Meta:
+ model = Schedule
+ fields = ["name", "owner","public","slug", "showings"]
+
diff --git a/movie_manager/views.py b/movie_manager/views.py
index d814302..e08d86e 100644
--- a/movie_manager/views.py
+++ b/movie_manager/views.py
@@ -1,17 +1,18 @@
-from django.http import HttpResponse, JsonResponse
+import datetime
+
+from django.http import JsonResponse
from django.contrib.auth.models import User
from rest_framework import permissions, viewsets
from knox.auth import TokenAuthentication
from rest_framework.decorators import action
from rest_framework.exceptions import NotFound
-from movie_manager.models import Movie, MovieList
-from movie_manager.serializers import MovieListSerializer, MovieSerializer
+from movie_manager.models import Movie, MovieList, Schedule, Showing
+from movie_manager.serializers import MovieListSerializer, MovieSerializer, ScheduleSerializer, ShowingSerializer
# Create your views here.
class MovieViewset(viewsets.ModelViewSet):
- fields = '__all__'
queryset = Movie.objects.all().order_by("title")
authentication_classes = [TokenAuthentication]
permission_classes = [permissions.IsAuthenticated]
@@ -19,7 +20,6 @@ class MovieViewset(viewsets.ModelViewSet):
serializer_class = MovieSerializer
class MovieListViewset(viewsets.ModelViewSet):
- fields = '__all__'
queryset = MovieList.objects.all().order_by("name")
authentication_classes = [TokenAuthentication]
permission_classes = [permissions.IsAuthenticated]
@@ -66,8 +66,73 @@ class MovieListViewset(viewsets.ModelViewSet):
return JsonResponse(MovieListSerializer(movie_list).data)
def remove_movie(self, request, pk=None, movie_id=None, *args, **kwargs):
- movie_list = MovieList.objects.get(pk=pk)
movie = Movie.objects.get(pk=movie_id)
+
+ movie_list = MovieList.objects.get(pk=pk)
movie_list.movies.remove(movie)
return JsonResponse(MovieListSerializer(movie_list).data)
+
+class ScheduleViewset(viewsets.ModelViewSet):
+ queryset = Schedule.objects.all().order_by("name")
+ authentication_classes = [TokenAuthentication]
+ permission_classes = [permissions.IsAuthenticated]
+
+ serializer_class = ScheduleSerializer
+
+ def retrieve(self, request, pk=None, *args, **kwargs):
+ # Get the schedule instance
+ instance = self.get_object()
+ today = datetime.datetime.now()
+
+ upcoming_showings = instance.showings.filter(showtime__gte=today)
+
+ # Create a serialized response
+ serializer = self.get_serializer(instance)
+ data = serializer.data
+
+ # Replace all showings with only future showings
+ data['showings'] = ShowingSerializer(upcoming_showings, many=True).data
+
+
+ if request.GET.get('past_showings') == 'true':
+ past_showings = instance.showings.filter(showtime__lt=today)
+
+ # Add both to the response
+ data['past_showings'] = [
+ {'id': showing.id, 'showtime': showing.showtime.isoformat(), "movie": MovieSerializer(showing.movie).data}
+ for showing in past_showings
+ ]
+ else:
+ data['past_showings'] = []
+
+ return JsonResponse(data)
+
+
+class ShowingViewset(viewsets.ModelViewSet):
+ queryset = Showing.objects.all().order_by("showtime")
+ authentication_classes = [TokenAuthentication]
+ permission_classes = [permissions.IsAuthenticated]
+
+ serializer_class = ShowingSerializer
+
+ def create(self, request, *args, **kwargs):
+ movie_id = request.data.get('movie')
+ movie = Movie.objects.get(pk=movie_id)
+
+ schedule_id = request.data.get('schedule')
+ schedule = Schedule.objects.get(pk=schedule_id)
+
+ showing = Showing.objects.create(
+ movie=movie,
+ schedule=schedule,
+ showtime=request.data.get("showtime"),
+ public=request.data.get("public"),
+ owner=User.objects.get(pk=request.data.get("owner"))
+ )
+
+ schedule.showings.add(showing)
+
+ return JsonResponse(ShowingSerializer(showing).data)
+
+
diff --git a/movienight/urls.py b/movienight/urls.py
index 1cb7bfd..6889ee7 100644
--- a/movienight/urls.py
+++ b/movienight/urls.py
@@ -19,6 +19,8 @@ router.register(r"api/users", user_views.UserViewSet)
router.register(r"api/groups", user_views.GroupViewSet)
router.register(r"api/movies", movie_views.MovieViewset)
router.register(r"api/lists", movie_views.MovieListViewset)
+router.register(r"api/schedules", movie_views.ScheduleViewset)
+router.register(r"api/showings", movie_views.ShowingViewset)
urlpatterns = [
path("", include(router.urls)),