From def55c2dcf6cffb9c5e59e078060013872f32e6b Mon Sep 17 00:00:00 2001 From: Vadym Sulim Date: Wed, 11 Dec 2024 16:29:26 +0200 Subject: [PATCH] 1f 2e --- .flake8 | 18 +- .github/workflows/test.yml | 64 +- .gitignore | 16 +- README.md | 350 +++---- checklist.md | 76 +- cinema/admin.py | 38 +- cinema/apps.py | 12 +- cinema/migrations/0001_initial.py | 298 +++--- cinema/migrations/0002_initial.py | 106 +- cinema/migrations/0003_movie_duration.py | 38 +- cinema/migrations/0004_alter_genre_name.py | 36 +- cinema/models.py | 217 ++-- cinema/serializers.py | 42 +- cinema/tests/test_actor_api.py | 146 +-- cinema/tests/test_cinema_hall_api.py | 260 ++--- cinema/tests/test_genre_api.py | 124 +-- cinema/tests/test_movie_api.py | 254 ++--- cinema/tests/test_movie_session_api.py | 158 +-- cinema/urls.py | 15 +- cinema/views.py | 31 +- cinema_service/asgi.py | 32 +- cinema_service/settings.py | 266 ++--- cinema_service/urls.py | 13 +- cinema_service/wsgi.py | 32 +- cinema_service_db_data.json | 1106 ++++++++++---------- manage.py | 44 +- requirements.txt | 10 +- user/admin.py | 10 +- user/apps.py | 12 +- user/migrations/0001_initial.py | 264 ++--- user/models.py | 10 +- user/tests.py | 6 +- 32 files changed, 2095 insertions(+), 2009 deletions(-) diff --git a/.flake8 b/.flake8 index b5381af3..bb4c976e 100644 --- a/.flake8 +++ b/.flake8 @@ -1,10 +1,10 @@ -[flake8] -inline-quotes = " -ignore = E203, E266, W503, N807, N818, F401 -max-line-length = 79 -max-complexity = 18 -select = B,C,E,F,W,T4,B9,Q0,N8,VNE -exclude = - **migrations - venv +[flake8] +inline-quotes = " +ignore = E203, E266, W503, N807, N818, F401 +max-line-length = 79 +max-complexity = 18 +select = B,C,E,F,W,T4,B9,Q0,N8,VNE +exclude = + **migrations + venv tests \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 116433a6..fcd19751 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,32 +1,32 @@ -name: Test - -on: - pull_request: - branches: - - "master" - -jobs: - test: - runs-on: ubuntu-latest - timeout-minutes: 10 - - steps: - - name: Checkout repo - uses: actions/checkout@v2 - - - name: Set Up Python 3.10 - uses: actions/setup-python@v2 - with: - python-version: "3.10" - - - name: Install requirements.txt - run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - - - name: Run flake8 - run: flake8 - - - name: Run tests - timeout-minutes: 5 - run: python manage.py test +name: Test + +on: + pull_request: + branches: + - "master" + +jobs: + test: + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - name: Checkout repo + uses: actions/checkout@v2 + + - name: Set Up Python 3.10 + uses: actions/setup-python@v2 + with: + python-version: "3.10" + + - name: Install requirements.txt + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + + - name: Run flake8 + run: flake8 + + - name: Run tests + timeout-minutes: 5 + run: python manage.py test diff --git a/.gitignore b/.gitignore index b26d6116..3bd421d1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,8 @@ -.idea/ -.vscode/ -*.iml -.env -.DS_Store -venv/ -.pytest_cache/ -**__pycache__/ +.idea/ +.vscode/ +*.iml +.env +.DS_Store +venv/ +.pytest_cache/ +**__pycache__/ diff --git a/README.md b/README.md index a8fe1ddf..d9a47309 100644 --- a/README.md +++ b/README.md @@ -1,175 +1,175 @@ -# API Serializers - -- Read [the guideline](https://github.com/mate-academy/py-task-guideline/blob/main/README.md) before starting. -- Use the following command to load prepared data from fixture to test and debug your code: - - `python manage.py loaddata cinema_service_db_data.json` - -In this task you will implement serializers and views for the following models: - -1. `Genre` -2. `Actor` -3. `CinemaHall` -4. `Movie` -5. `MovieSession` - -For every `` from `actors`, `genres`, `cinema_halls`, `movies`, `movie_sessions` such -endpoints should be implemented: -* `GET api/cinema//` - should return a list of the all entity items -* `POST api/cinema//` - should create a new entity based on passed data -* `GET api/cinema///` - should return an entity with given id -* `PUT api/cinema///` - should update the entity with given id based on passed data -* `DELETE api/cinema///` - should delete the entity with given id - -Additional requirements: -1. For the list movie endpoint, genres and actors should be returned as lists of strings. -`"genres"` list should contain names of the genres, and the `"actors"` list should contain full names of actors and actresses. -Example: -``` -GET api/cinema/movies/ -``` - -``` -HTTP 200 OK -Allow: GET, POST, HEAD, OPTIONS -Content-Type: application/json -Vary: Accept - -[ - { - "id": 1, - "title": "Harry Potter and the Philosopher's Stone", - "description": "The first movie about Harry Potter", - "duration": 210, - "genres": [ - "drama" - ], - "actors": [ - "Emma Watson", - "Daniel Radcliffe" - ] - } -] -``` -2. At the same time movie detail endpoint should provide complete information about the genres and actors. - -Example: -``` -GET /api/cinema/movies/1/ -``` - -``` -HTTP 200 OK -Allow: GET, PUT, PATCH, DELETE, HEAD, OPTIONS -Content-Type: application/json -Vary: Accept - -{ - "id": 1, - "title": "Harry Potter and the Philosopher's Stone", - "description": "The first movie about Harry Potter", - "duration": 210, - "genres": [ - { - "id": 1, - "name": "drama" - } - ], - "actors": [ - { - "id": 1, - "first_name": "Emma", - "last_name": "Watson", - "full_name": "Emma Watson" - }, - { - "id": 2, - "first_name": "Daniel", - "last_name": "Radcliffe", - "full_name": "Daniel Radcliffe" - } - ] -} -``` - -3. For `movies_session` list endpoint you should return the following information: - * `"id"` - the id of the movie session; - * `"show_time"` - the start time of the session - * `"movie_title"` - the title of the movie - * `"cinema_hall_name"` - the name of the cinema hall for the session - * `"cinema_hall_capacity"` - the capacity of the cinema hall for the session - -Example: -``` -GET /api/cinema/movie_sessions/ -``` - -``` -HTTP 200 OK -Allow: GET, POST, HEAD, OPTIONS -Content-Type: application/json -Vary: Accept - -[ - { - "id": 2, - "show_time": "2023-07-22T12:15:00Z", - "movie_title": "Harry Potter and the Prisoner of Azkaban", - "cinema_hall_name": "Green", - "cinema_hall_capacity": 150 - }, - { - "id": 1, - "show_time": "2022-06-15T12:25:00Z", - "movie_title": "Harry Potter and the Philosopher's Stone", - "cinema_hall_name": "Black", - "cinema_hall_capacity": 300 - } -] -``` - -4. At the same time for the movie session detail endpoint, complete information about the movie should be provided. - -Example: -``` -GET /api/cinema/movie_sessions/1/ -``` - -``` -HTTP 200 OK -Allow: GET, PUT, PATCH, DELETE, HEAD, OPTIONS -Content-Type: application/json -Vary: Accept - -{ - "id": 1, - "show_time": "2022-06-15T12:25:00Z", - "movie": { - "id": 1, - "title": "Harry Potter and the Philosopher's Stone", - "description": "The first movie about Harry Potter", - "duration": 210, - "genres": [ - "drama" - ], - "actors": [ - "Emma Watson", - "Daniel Radcliffe" - ] - }, - "cinema_hall": { - "id": 2, - "name": "Black", - "rows": 20, - "seats_in_row": 15, - "capacity": 300 - } -} -``` - - -Hint: Use `ModelViewSet` to create views. - -Run tests through the terminal using `pytest` - -### Note: Check your code using this [checklist](checklist.md) before pushing your solution. +# API Serializers + +- Read [the guideline](https://github.com/mate-academy/py-task-guideline/blob/main/README.md) before starting. +- Use the following command to load prepared data from fixture to test and debug your code: + + `python manage.py loaddata cinema_service_db_data.json` + +In this task you will implement serializers and views for the following models: + +1. `Genre` +2. `Actor` +3. `CinemaHall` +4. `Movie` +5. `MovieSession` + +For every `` from `actors`, `genres`, `cinema_halls`, `movies`, `movie_sessions` such +endpoints should be implemented: +* `GET api/cinema//` - should return a list of the all entity items +* `POST api/cinema//` - should create a new entity based on passed data +* `GET api/cinema///` - should return an entity with given id +* `PUT api/cinema///` - should update the entity with given id based on passed data +* `DELETE api/cinema///` - should delete the entity with given id + +Additional requirements: +1. For the list movie endpoint, genres and actors should be returned as lists of strings. +`"genres"` list should contain names of the genres, and the `"actors"` list should contain full names of actors and actresses. +Example: +``` +GET api/cinema/movies/ +``` + +``` +HTTP 200 OK +Allow: GET, POST, HEAD, OPTIONS +Content-Type: application/json +Vary: Accept + +[ + { + "id": 1, + "title": "Harry Potter and the Philosopher's Stone", + "description": "The first movie about Harry Potter", + "duration": 210, + "genres": [ + "drama" + ], + "actors": [ + "Emma Watson", + "Daniel Radcliffe" + ] + } +] +``` +2. At the same time movie detail endpoint should provide complete information about the genres and actors. + +Example: +``` +GET /api/cinema/movies/1/ +``` + +``` +HTTP 200 OK +Allow: GET, PUT, PATCH, DELETE, HEAD, OPTIONS +Content-Type: application/json +Vary: Accept + +{ + "id": 1, + "title": "Harry Potter and the Philosopher's Stone", + "description": "The first movie about Harry Potter", + "duration": 210, + "genres": [ + { + "id": 1, + "name": "drama" + } + ], + "actors": [ + { + "id": 1, + "first_name": "Emma", + "last_name": "Watson", + "full_name": "Emma Watson" + }, + { + "id": 2, + "first_name": "Daniel", + "last_name": "Radcliffe", + "full_name": "Daniel Radcliffe" + } + ] +} +``` + +3. For `movies_session` list endpoint you should return the following information: + * `"id"` - the id of the movie session; + * `"show_time"` - the start time of the session + * `"movie_title"` - the title of the movie + * `"cinema_hall_name"` - the name of the cinema hall for the session + * `"cinema_hall_capacity"` - the capacity of the cinema hall for the session + +Example: +``` +GET /api/cinema/movie_sessions/ +``` + +``` +HTTP 200 OK +Allow: GET, POST, HEAD, OPTIONS +Content-Type: application/json +Vary: Accept + +[ + { + "id": 2, + "show_time": "2023-07-22T12:15:00Z", + "movie_title": "Harry Potter and the Prisoner of Azkaban", + "cinema_hall_name": "Green", + "cinema_hall_capacity": 150 + }, + { + "id": 1, + "show_time": "2022-06-15T12:25:00Z", + "movie_title": "Harry Potter and the Philosopher's Stone", + "cinema_hall_name": "Black", + "cinema_hall_capacity": 300 + } +] +``` + +4. At the same time for the movie session detail endpoint, complete information about the movie should be provided. + +Example: +``` +GET /api/cinema/movie_sessions/1/ +``` + +``` +HTTP 200 OK +Allow: GET, PUT, PATCH, DELETE, HEAD, OPTIONS +Content-Type: application/json +Vary: Accept + +{ + "id": 1, + "show_time": "2022-06-15T12:25:00Z", + "movie": { + "id": 1, + "title": "Harry Potter and the Philosopher's Stone", + "description": "The first movie about Harry Potter", + "duration": 210, + "genres": [ + "drama" + ], + "actors": [ + "Emma Watson", + "Daniel Radcliffe" + ] + }, + "cinema_hall": { + "id": 2, + "name": "Black", + "rows": 20, + "seats_in_row": 15, + "capacity": 300 + } +} +``` + + +Hint: Use `ModelViewSet` to create views. + +Run tests through the terminal using `pytest` + +### Note: Check your code using this [checklist](checklist.md) before pushing your solution. diff --git a/checklist.md b/checklist.md index fbda0a34..4f61559c 100644 --- a/checklist.md +++ b/checklist.md @@ -1,38 +1,38 @@ -# Check Your Code Against the Following Points - -## Code Style - -1. Do not forget about type annotation in class methods. - -2. You do not need `.all()` method before -`.prefetch_related()` and `.select_related()` methods: - -Good example: - -```python -queryset = Movie.objects.prefetch_related("actors") -``` - -Bad example: - -```python -queryset = Movie.objects.all().prefetch_related("actors") -``` - -3. You can provide multiple arguments into prefetch_related method: - -Good example: - -```python -queryset = Movie.objects.prefetch_related("actors", "genres") -``` - -Bad example: - -```python -queryset = Movie.objects.prefetch_related("actors").prefetch_related("genres") -``` - -## Clean Code -Add comments, prints, and functions to check your solution when you write your code. -Don't forget to delete them when you are ready to commit and push your code. +# Check Your Code Against the Following Points + +## Code Style + +1. Do not forget about type annotation in class methods. + +2. You do not need `.all()` method before +`.prefetch_related()` and `.select_related()` methods: + +Good example: + +```python +queryset = Movie.objects.prefetch_related("actors") +``` + +Bad example: + +```python +queryset = Movie.objects.all().prefetch_related("actors") +``` + +3. You can provide multiple arguments into prefetch_related method: + +Good example: + +```python +queryset = Movie.objects.prefetch_related("actors", "genres") +``` + +Bad example: + +```python +queryset = Movie.objects.prefetch_related("actors").prefetch_related("genres") +``` + +## Clean Code +Add comments, prints, and functions to check your solution when you write your code. +Don't forget to delete them when you are ready to commit and push your code. diff --git a/cinema/admin.py b/cinema/admin.py index 0b288331..1b2ed53e 100644 --- a/cinema/admin.py +++ b/cinema/admin.py @@ -1,19 +1,19 @@ -from django.contrib import admin - -from .models import ( - CinemaHall, - Genre, - Actor, - Movie, - MovieSession, - Order, - Ticket, -) - -admin.site.register(CinemaHall) -admin.site.register(Genre) -admin.site.register(Actor) -admin.site.register(Movie) -admin.site.register(MovieSession) -admin.site.register(Order) -admin.site.register(Ticket) +from django.contrib import admin + +from .models import ( + CinemaHall, + Genre, + Actor, + Movie, + MovieSession, + Order, + Ticket, +) + +admin.site.register(CinemaHall) +admin.site.register(Genre) +admin.site.register(Actor) +admin.site.register(Movie) +admin.site.register(MovieSession) +admin.site.register(Order) +admin.site.register(Ticket) diff --git a/cinema/apps.py b/cinema/apps.py index c730aa2b..b3adbc13 100644 --- a/cinema/apps.py +++ b/cinema/apps.py @@ -1,6 +1,6 @@ -from django.apps import AppConfig - - -class CinemaConfig(AppConfig): - default_auto_field = "django.db.models.BigAutoField" - name = "cinema" +from django.apps import AppConfig + + +class CinemaConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "cinema" diff --git a/cinema/migrations/0001_initial.py b/cinema/migrations/0001_initial.py index ef841f46..f8ac275c 100644 --- a/cinema/migrations/0001_initial.py +++ b/cinema/migrations/0001_initial.py @@ -1,149 +1,149 @@ -# Generated by Django 4.0.4 on 2022-05-09 18:11 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [] - - operations = [ - migrations.CreateModel( - name="Actor", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("first_name", models.CharField(max_length=255)), - ("last_name", models.CharField(max_length=255)), - ], - ), - migrations.CreateModel( - name="CinemaHall", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("name", models.CharField(max_length=255)), - ("rows", models.IntegerField()), - ("seats_in_row", models.IntegerField()), - ], - ), - migrations.CreateModel( - name="Genre", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("name", models.CharField(max_length=255)), - ], - ), - migrations.CreateModel( - name="Movie", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("title", models.CharField(max_length=255)), - ("description", models.TextField()), - ], - options={ - "ordering": ["title"], - }, - ), - migrations.CreateModel( - name="MovieSession", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("show_time", models.DateTimeField()), - ], - options={ - "ordering": ["-show_time"], - }, - ), - migrations.CreateModel( - name="Order", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("created_at", models.DateTimeField(auto_now_add=True)), - ], - options={ - "ordering": ["-created_at"], - }, - ), - migrations.CreateModel( - name="Ticket", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("row", models.IntegerField()), - ("seat", models.IntegerField()), - ( - "movie_session", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="tickets", - to="cinema.moviesession", - ), - ), - ( - "order", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="tickets", - to="cinema.order", - ), - ), - ], - ), - ] +# Generated by Django 4.0.4 on 2022-05-09 18:11 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [] + + operations = [ + migrations.CreateModel( + name="Actor", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("first_name", models.CharField(max_length=255)), + ("last_name", models.CharField(max_length=255)), + ], + ), + migrations.CreateModel( + name="CinemaHall", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=255)), + ("rows", models.IntegerField()), + ("seats_in_row", models.IntegerField()), + ], + ), + migrations.CreateModel( + name="Genre", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=255)), + ], + ), + migrations.CreateModel( + name="Movie", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("title", models.CharField(max_length=255)), + ("description", models.TextField()), + ], + options={ + "ordering": ["title"], + }, + ), + migrations.CreateModel( + name="MovieSession", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("show_time", models.DateTimeField()), + ], + options={ + "ordering": ["-show_time"], + }, + ), + migrations.CreateModel( + name="Order", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("created_at", models.DateTimeField(auto_now_add=True)), + ], + options={ + "ordering": ["-created_at"], + }, + ), + migrations.CreateModel( + name="Ticket", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("row", models.IntegerField()), + ("seat", models.IntegerField()), + ( + "movie_session", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="tickets", + to="cinema.moviesession", + ), + ), + ( + "order", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="tickets", + to="cinema.order", + ), + ), + ], + ), + ] diff --git a/cinema/migrations/0002_initial.py b/cinema/migrations/0002_initial.py index e6341fe7..ca8d5456 100644 --- a/cinema/migrations/0002_initial.py +++ b/cinema/migrations/0002_initial.py @@ -1,53 +1,53 @@ -# Generated by Django 4.0.4 on 2022-05-09 18:11 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ("cinema", "0001_initial"), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.AddField( - model_name="order", - name="user", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL - ), - ), - migrations.AddField( - model_name="moviesession", - name="cinema_hall", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="cinema.cinemahall" - ), - ), - migrations.AddField( - model_name="moviesession", - name="movie", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="cinema.movie" - ), - ), - migrations.AddField( - model_name="movie", - name="actors", - field=models.ManyToManyField(to="cinema.actor"), - ), - migrations.AddField( - model_name="movie", - name="genres", - field=models.ManyToManyField(to="cinema.genre"), - ), - migrations.AlterUniqueTogether( - name="ticket", - unique_together={("movie_session", "row", "seat")}, - ), - ] +# Generated by Django 4.0.4 on 2022-05-09 18:11 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ("cinema", "0001_initial"), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AddField( + model_name="order", + name="user", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL + ), + ), + migrations.AddField( + model_name="moviesession", + name="cinema_hall", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="cinema.cinemahall" + ), + ), + migrations.AddField( + model_name="moviesession", + name="movie", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="cinema.movie" + ), + ), + migrations.AddField( + model_name="movie", + name="actors", + field=models.ManyToManyField(to="cinema.actor"), + ), + migrations.AddField( + model_name="movie", + name="genres", + field=models.ManyToManyField(to="cinema.genre"), + ), + migrations.AlterUniqueTogether( + name="ticket", + unique_together={("movie_session", "row", "seat")}, + ), + ] diff --git a/cinema/migrations/0003_movie_duration.py b/cinema/migrations/0003_movie_duration.py index 7355c91a..7c9d96ca 100644 --- a/cinema/migrations/0003_movie_duration.py +++ b/cinema/migrations/0003_movie_duration.py @@ -1,19 +1,19 @@ -# Generated by Django 4.0.4 on 2022-05-10 12:50 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('cinema', '0002_initial'), - ] - - operations = [ - migrations.AddField( - model_name='movie', - name='duration', - field=models.IntegerField(default=123), - preserve_default=False, - ), - ] +# Generated by Django 4.0.4 on 2022-05-10 12:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('cinema', '0002_initial'), + ] + + operations = [ + migrations.AddField( + model_name='movie', + name='duration', + field=models.IntegerField(default=123), + preserve_default=False, + ), + ] diff --git a/cinema/migrations/0004_alter_genre_name.py b/cinema/migrations/0004_alter_genre_name.py index 0a4d429e..a1698c91 100644 --- a/cinema/migrations/0004_alter_genre_name.py +++ b/cinema/migrations/0004_alter_genre_name.py @@ -1,18 +1,18 @@ -# Generated by Django 4.0.4 on 2022-06-16 08:42 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('cinema', '0003_movie_duration'), - ] - - operations = [ - migrations.AlterField( - model_name='genre', - name='name', - field=models.CharField(max_length=255, unique=True), - ), - ] +# Generated by Django 4.0.4 on 2022-06-16 08:42 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('cinema', '0003_movie_duration'), + ] + + operations = [ + migrations.AlterField( + model_name='genre', + name='name', + field=models.CharField(max_length=255, unique=True), + ), + ] diff --git a/cinema/models.py b/cinema/models.py index c42d2a3d..c4b0bc1c 100644 --- a/cinema/models.py +++ b/cinema/models.py @@ -1,107 +1,110 @@ -from django.core.exceptions import ValidationError -from django.db import models -from django.conf import settings - - -class CinemaHall(models.Model): - name = models.CharField(max_length=255) - rows = models.IntegerField() - seats_in_row = models.IntegerField() - - @property - def capacity(self) -> int: - return self.rows * self.seats_in_row - - def __str__(self): - return self.name - - -class Genre(models.Model): - name = models.CharField(max_length=255, unique=True) - - def __str__(self): - return self.name - - -class Actor(models.Model): - first_name = models.CharField(max_length=255) - last_name = models.CharField(max_length=255) - - def __str__(self): - return self.first_name + " " + self.last_name - - -class Movie(models.Model): - title = models.CharField(max_length=255) - description = models.TextField() - duration = models.IntegerField() - genres = models.ManyToManyField(Genre) - actors = models.ManyToManyField(Actor) - - class Meta: - ordering = ["title"] - - def __str__(self): - return self.title - - -class MovieSession(models.Model): - show_time = models.DateTimeField() - movie = models.ForeignKey(Movie, on_delete=models.CASCADE) - cinema_hall = models.ForeignKey(CinemaHall, on_delete=models.CASCADE) - - class Meta: - ordering = ["-show_time"] - - def __str__(self): - return self.movie.title + " " + str(self.show_time) - - -class Order(models.Model): - created_at = models.DateTimeField(auto_now_add=True) - user = models.ForeignKey( - settings.AUTH_USER_MODEL, on_delete=models.CASCADE - ) - - def __str__(self): - return str(self.created_at) - - class Meta: - ordering = ["-created_at"] - - -class Ticket(models.Model): - movie_session = models.ForeignKey( - MovieSession, on_delete=models.CASCADE, related_name="tickets" - ) - order = models.ForeignKey( - Order, on_delete=models.CASCADE, related_name="tickets" - ) - row = models.IntegerField() - seat = models.IntegerField() - - def clean(self): - for ticket_attr_value, ticket_attr_name, cinema_hall_attr_name in [ - (self.row, "row", "count_rows"), - (self.seat, "seat", "count_seats_in_row"), - ]: - count_attrs = getattr( - self.movie_session.cinema_hall, cinema_hall_attr_name - ) - if not (1 <= ticket_attr_value <= count_attrs): - raise ValidationError( - { - ticket_attr_name: f"{ticket_attr_name} number " - f"must be in available range: " - f"(1, {cinema_hall_attr_name}): " - f"(1, {count_attrs})" - } - ) - - def __str__(self): - return ( - f"{str(self.movie_session)} (row: {self.row}, seat: {self.seat})" - ) - - class Meta: - unique_together = ("movie_session", "row", "seat") +from django.core.exceptions import ValidationError +from django.db import models +from django.conf import settings + + +class CinemaHall(models.Model): + name = models.CharField(max_length=255) + rows = models.IntegerField() + seats_in_row = models.IntegerField() + + @property + def capacity(self) -> int: + return self.rows * self.seats_in_row + + def __str__(self): + return self.name + + +class Genre(models.Model): + name = models.CharField(max_length=255, unique=True) + + def __str__(self): + return self.name + + +class Actor(models.Model): + first_name = models.CharField(max_length=255) + last_name = models.CharField(max_length=255) + + def get_full_name(self): + return self.first_name + " " + self.last_name + + def __str__(self): + return self.first_name + " " + self.last_name + + +class Movie(models.Model): + title = models.CharField(max_length=255) + description = models.TextField() + duration = models.IntegerField() + genres = models.ManyToManyField(Genre) + actors = models.ManyToManyField(Actor) + + class Meta: + ordering = ["title"] + + def __str__(self): + return self.title + + +class MovieSession(models.Model): + show_time = models.DateTimeField() + movie = models.ForeignKey(Movie, on_delete=models.CASCADE) + cinema_hall = models.ForeignKey(CinemaHall, on_delete=models.CASCADE) + + class Meta: + ordering = ["-show_time"] + + def __str__(self): + return self.movie.title + " " + str(self.show_time) + + +class Order(models.Model): + created_at = models.DateTimeField(auto_now_add=True) + user = models.ForeignKey( + settings.AUTH_USER_MODEL, on_delete=models.CASCADE + ) + + def __str__(self): + return str(self.created_at) + + class Meta: + ordering = ["-created_at"] + + +class Ticket(models.Model): + movie_session = models.ForeignKey( + MovieSession, on_delete=models.CASCADE, related_name="tickets" + ) + order = models.ForeignKey( + Order, on_delete=models.CASCADE, related_name="tickets" + ) + row = models.IntegerField() + seat = models.IntegerField() + + def clean(self): + for ticket_attr_value, ticket_attr_name, cinema_hall_attr_name in [ + (self.row, "row", "count_rows"), + (self.seat, "seat", "count_seats_in_row"), + ]: + count_attrs = getattr( + self.movie_session.cinema_hall, cinema_hall_attr_name + ) + if not (1 <= ticket_attr_value <= count_attrs): + raise ValidationError( + { + ticket_attr_name: f"{ticket_attr_name} number " + f"must be in available range: " + f"(1, {cinema_hall_attr_name}): " + f"(1, {count_attrs})" + } + ) + + def __str__(self): + return ( + f"{str(self.movie_session)} (row: {self.row}, seat: {self.seat})" + ) + + class Meta: + unique_together = ("movie_session", "row", "seat") diff --git a/cinema/serializers.py b/cinema/serializers.py index 612ca7e2..cded6a55 100644 --- a/cinema/serializers.py +++ b/cinema/serializers.py @@ -1 +1,41 @@ -# write serializers here +from rest_framework import serializers + +from cinema.models import Genre, Actor, CinemaHall, Movie, MovieSession + + +class GenreSerializer(serializers.ModelSerializer): + class Meta: + model = Genre + fields = ["id", "name"] + + +class ActorSerializer(serializers.ModelSerializer): + full_name = serializers.CharField(source="get_full_name", read_only=True) + + class Meta: + model = Actor + fields = ["id", "first_name", "last_name", "full_name"] + + +class CinemaHallSerializer(serializers.ModelSerializer): + capacity = serializers.IntegerField(read_only=True) + + class Meta: + model = CinemaHall + fields = ["id", "name", "rows", "seats_in_row", "capacity"] + + +class MovieSerializer(serializers.ModelSerializer): + class Meta: + model = Movie + fields = ["id", "title", "description", "duration", "genres", "actors"] + + +class MovieSessionSerializer(serializers.ModelSerializer): + movie_title = serializers.CharField(source="movie.title", read_only=True) + cinema_hall_name = serializers.CharField(source="cinema_hall.name", read_only=True) + cinema_hall_capacity = serializers.IntegerField(source="cinema_hall.capacity", read_only=True) + + class Meta: + model = MovieSession + fields = ["id", "show_time", "movie", "cinema_hall", "movie_title", "cinema_hall_name", "cinema_hall_capacity"] diff --git a/cinema/tests/test_actor_api.py b/cinema/tests/test_actor_api.py index 3fa7a469..1297b88c 100644 --- a/cinema/tests/test_actor_api.py +++ b/cinema/tests/test_actor_api.py @@ -1,73 +1,73 @@ -from django.test import TestCase - -from rest_framework import status -from rest_framework.test import APIClient - -from cinema.models import Actor - - -class ActorApiTests(TestCase): - def setUp(self): - self.client = APIClient() - Actor.objects.create(first_name="George", last_name="Clooney") - Actor.objects.create(first_name="Keanu", last_name="Reeves") - - def test_get_actors(self): - response = self.client.get("/api/cinema/actors/") - self.assertEqual(response.status_code, status.HTTP_200_OK) - actors_full_names = [actor["full_name"] for actor in response.data] - self.assertEqual( - sorted(actors_full_names), ["George Clooney", "Keanu Reeves"] - ) - - def test_post_actors(self): - response = self.client.post( - "/api/cinema/actors/", - { - "first_name": "Scarlett", - "last_name": "Johansson", - }, - ) - db_actors = Actor.objects.all() - self.assertEqual(response.status_code, status.HTTP_201_CREATED) - self.assertEqual(db_actors.count(), 3) - self.assertEqual(db_actors.filter(first_name="Scarlett").count(), 1) - - def test_get_invalid_actor(self): - response = self.client.get("/api/cinema/actors/1001/") - self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) - - def test_put_actor(self): - response = self.client.put( - "/api/cinema/actors/1/", - { - "first_name": "Scarlett", - "last_name": "Johansson", - }, - ) - actor_pk_1 = Actor.objects.get(pk=1) - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - [ - actor_pk_1.first_name, - actor_pk_1.last_name, - ], - [ - "Scarlett", - "Johansson", - ], - ) - - def test_delete_actor(self): - response = self.client.delete( - "/api/cinema/actors/1/", - ) - db_actors_id_1 = Actor.objects.filter(id=1) - self.assertEqual(db_actors_id_1.count(), 0) - self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) - - def test_delete_invalid_actor(self): - response = self.client.delete( - "/api/cinema/actors/1000/", - ) - self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) +from django.test import TestCase + +from rest_framework import status +from rest_framework.test import APIClient + +from cinema.models import Actor + + +class ActorApiTests(TestCase): + def setUp(self): + self.client = APIClient() + Actor.objects.create(first_name="George", last_name="Clooney") + Actor.objects.create(first_name="Keanu", last_name="Reeves") + + def test_get_actors(self): + response = self.client.get("/api/cinema/actors/") + self.assertEqual(response.status_code, status.HTTP_200_OK) + actors_full_names = [actor["full_name"] for actor in response.data] + self.assertEqual( + sorted(actors_full_names), ["George Clooney", "Keanu Reeves"] + ) + + def test_post_actors(self): + response = self.client.post( + "/api/cinema/actors/", + { + "first_name": "Scarlett", + "last_name": "Johansson", + }, + ) + db_actors = Actor.objects.all() + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + self.assertEqual(db_actors.count(), 3) + self.assertEqual(db_actors.filter(first_name="Scarlett").count(), 1) + + def test_get_invalid_actor(self): + response = self.client.get("/api/cinema/actors/1001/") + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + + def test_put_actor(self): + response = self.client.put( + "/api/cinema/actors/1/", + { + "first_name": "Scarlett", + "last_name": "Johansson", + }, + ) + actor_pk_1 = Actor.objects.get(pk=1) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual( + [ + actor_pk_1.first_name, + actor_pk_1.last_name, + ], + [ + "Scarlett", + "Johansson", + ], + ) + + def test_delete_actor(self): + response = self.client.delete( + "/api/cinema/actors/1/", + ) + db_actors_id_1 = Actor.objects.filter(id=1) + self.assertEqual(db_actors_id_1.count(), 0) + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) + + def test_delete_invalid_actor(self): + response = self.client.delete( + "/api/cinema/actors/1000/", + ) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) diff --git a/cinema/tests/test_cinema_hall_api.py b/cinema/tests/test_cinema_hall_api.py index d3e9ea77..8e0aee12 100644 --- a/cinema/tests/test_cinema_hall_api.py +++ b/cinema/tests/test_cinema_hall_api.py @@ -1,130 +1,130 @@ -from django.test import TestCase - -from rest_framework.test import APIClient -from rest_framework import status - -from cinema.models import CinemaHall - - -class CinemaHallApiTests(TestCase): - def setUp(self): - self.client = APIClient() - CinemaHall.objects.create( - name="Blue", - rows=15, - seats_in_row=20, - ) - CinemaHall.objects.create( - name="VIP", - rows=6, - seats_in_row=8, - ) - - def test_get_cinema_halls(self): - response = self.client.get("/api/cinema/cinema_halls/") - blue_hall = { - "name": "Blue", - "rows": 15, - "seats_in_row": 20, - "capacity": 300, - } - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data[0]["name"], blue_hall["name"]) - self.assertEqual(response.data[0]["rows"], blue_hall["rows"]) - self.assertEqual( - response.data[0]["seats_in_row"], blue_hall["seats_in_row"] - ) - vip_hall = { - "name": "VIP", - "rows": 6, - "seats_in_row": 8, - "capacity": 48, - } - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data[1]["name"], vip_hall["name"]) - self.assertEqual(response.data[1]["rows"], vip_hall["rows"]) - self.assertEqual( - response.data[1]["seats_in_row"], vip_hall["seats_in_row"] - ) - - def test_post_cinema_halls(self): - response = self.client.post( - "/api/cinema/cinema_halls/", - { - "name": "Yellow", - "rows": 14, - "seats_in_row": 15, - }, - ) - db_cinema_halls = CinemaHall.objects.all() - self.assertEqual(response.status_code, status.HTTP_201_CREATED) - self.assertEqual(db_cinema_halls.count(), 3) - self.assertEqual(db_cinema_halls.filter(name="Yellow").count(), 1) - - def test_get_cinema_hall(self): - response = self.client.get("/api/cinema/cinema_halls/2/") - vip_hall = { - "name": "VIP", - "rows": 6, - "seats_in_row": 8, - "capacity": 48, - } - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data["name"], vip_hall["name"]) - self.assertEqual(response.data["rows"], vip_hall["rows"]) - self.assertEqual( - response.data["seats_in_row"], vip_hall["seats_in_row"] - ) - self.assertEqual(response.data["capacity"], vip_hall["capacity"]) - - def test_get_invalid_cinema_hall(self): - response = self.client.get("/api/cinema/cinema_halls/1001/") - self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) - - def test_put_cinema_hall(self): - response = self.client.put( - "/api/cinema/cinema_halls/1/", - { - "name": "Yellow", - "rows": 14, - "seats_in_row": 15, - }, - ) - cinema_hall_pk_1 = CinemaHall.objects.get(pk=1) - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - [ - cinema_hall_pk_1.name, - cinema_hall_pk_1.rows, - cinema_hall_pk_1.seats_in_row, - ], - [ - "Yellow", - 14, - 15, - ], - ) - - def test_patch_cinema_hall(self): - response = self.client.patch( - "/api/cinema/cinema_halls/1/", - { - "name": "Green", - }, - ) - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(CinemaHall.objects.get(id=1).name, "Green") - - def test_delete_cinema_hall(self): - response = self.client.delete( - "/api/cinema/cinema_halls/1/", - ) - db_cinema_halls_id_1 = CinemaHall.objects.filter(id=1) - self.assertEqual(db_cinema_halls_id_1.count(), 0) - self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) - - def test_delete_invalid_cinema_hall(self): - response = self.client.delete( - "/api/cinema/cinema_halls/1000/", - ) - self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) +from django.test import TestCase + +from rest_framework.test import APIClient +from rest_framework import status + +from cinema.models import CinemaHall + + +class CinemaHallApiTests(TestCase): + def setUp(self): + self.client = APIClient() + CinemaHall.objects.create( + name="Blue", + rows=15, + seats_in_row=20, + ) + CinemaHall.objects.create( + name="VIP", + rows=6, + seats_in_row=8, + ) + + def test_get_cinema_halls(self): + response = self.client.get("/api/cinema/cinema_halls/") + blue_hall = { + "name": "Blue", + "rows": 15, + "seats_in_row": 20, + "capacity": 300, + } + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data[0]["name"], blue_hall["name"]) + self.assertEqual(response.data[0]["rows"], blue_hall["rows"]) + self.assertEqual( + response.data[0]["seats_in_row"], blue_hall["seats_in_row"] + ) + vip_hall = { + "name": "VIP", + "rows": 6, + "seats_in_row": 8, + "capacity": 48, + } + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data[1]["name"], vip_hall["name"]) + self.assertEqual(response.data[1]["rows"], vip_hall["rows"]) + self.assertEqual( + response.data[1]["seats_in_row"], vip_hall["seats_in_row"] + ) + + def test_post_cinema_halls(self): + response = self.client.post( + "/api/cinema/cinema_halls/", + { + "name": "Yellow", + "rows": 14, + "seats_in_row": 15, + }, + ) + db_cinema_halls = CinemaHall.objects.all() + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + self.assertEqual(db_cinema_halls.count(), 3) + self.assertEqual(db_cinema_halls.filter(name="Yellow").count(), 1) + + def test_get_cinema_hall(self): + response = self.client.get("/api/cinema/cinema_halls/2/") + vip_hall = { + "name": "VIP", + "rows": 6, + "seats_in_row": 8, + "capacity": 48, + } + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data["name"], vip_hall["name"]) + self.assertEqual(response.data["rows"], vip_hall["rows"]) + self.assertEqual( + response.data["seats_in_row"], vip_hall["seats_in_row"] + ) + self.assertEqual(response.data["capacity"], vip_hall["capacity"]) + + def test_get_invalid_cinema_hall(self): + response = self.client.get("/api/cinema/cinema_halls/1001/") + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + + def test_put_cinema_hall(self): + response = self.client.put( + "/api/cinema/cinema_halls/1/", + { + "name": "Yellow", + "rows": 14, + "seats_in_row": 15, + }, + ) + cinema_hall_pk_1 = CinemaHall.objects.get(pk=1) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual( + [ + cinema_hall_pk_1.name, + cinema_hall_pk_1.rows, + cinema_hall_pk_1.seats_in_row, + ], + [ + "Yellow", + 14, + 15, + ], + ) + + def test_patch_cinema_hall(self): + response = self.client.patch( + "/api/cinema/cinema_halls/1/", + { + "name": "Green", + }, + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(CinemaHall.objects.get(id=1).name, "Green") + + def test_delete_cinema_hall(self): + response = self.client.delete( + "/api/cinema/cinema_halls/1/", + ) + db_cinema_halls_id_1 = CinemaHall.objects.filter(id=1) + self.assertEqual(db_cinema_halls_id_1.count(), 0) + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) + + def test_delete_invalid_cinema_hall(self): + response = self.client.delete( + "/api/cinema/cinema_halls/1000/", + ) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) diff --git a/cinema/tests/test_genre_api.py b/cinema/tests/test_genre_api.py index a81daaf4..f7abd263 100644 --- a/cinema/tests/test_genre_api.py +++ b/cinema/tests/test_genre_api.py @@ -1,62 +1,62 @@ -from django.test import TestCase - -from rest_framework import status -from rest_framework.test import APIClient - -from cinema.models import Genre - - -class GenreApiTests(TestCase): - def setUp(self): - self.client = APIClient() - Genre.objects.create( - name="Comedy", - ) - Genre.objects.create( - name="Drama", - ) - - def test_get_genres(self): - response = self.client.get("/api/cinema/genres/") - genres = [genre["name"] for genre in response.data] - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(sorted(genres), ["Comedy", "Drama"]) - - def test_post_genres(self): - response = self.client.post( - "/api/cinema/genres/", - { - "name": "Sci-fi", - }, - ) - db_genres = Genre.objects.all() - self.assertEqual(response.status_code, status.HTTP_201_CREATED) - self.assertEqual(db_genres.count(), 3) - self.assertEqual(db_genres.filter(name="Sci-fi").count(), 1) - - def test_get_invalid_genre(self): - response = self.client.get("/api/cinema/genres/1001/") - self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) - - def test_put_genre(self): - response = self.client.put( - "/api/cinema/genres/1/", - { - "name": "Sci-fi", - }, - ) - self.assertEqual(response.status_code, status.HTTP_200_OK) - - def test_delete_genre(self): - response = self.client.delete( - "/api/cinema/genres/1/", - ) - db_genres_id_1 = Genre.objects.filter(id=1) - self.assertEqual(db_genres_id_1.count(), 0) - self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) - - def test_delete_invalid_genre(self): - response = self.client.delete( - "/api/cinema/genres/1000/", - ) - self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) +from django.test import TestCase + +from rest_framework import status +from rest_framework.test import APIClient + +from cinema.models import Genre + + +class GenreApiTests(TestCase): + def setUp(self): + self.client = APIClient() + Genre.objects.create( + name="Comedy", + ) + Genre.objects.create( + name="Drama", + ) + + def test_get_genres(self): + response = self.client.get("/api/cinema/genres/") + genres = [genre["name"] for genre in response.data] + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(sorted(genres), ["Comedy", "Drama"]) + + def test_post_genres(self): + response = self.client.post( + "/api/cinema/genres/", + { + "name": "Sci-fi", + }, + ) + db_genres = Genre.objects.all() + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + self.assertEqual(db_genres.count(), 3) + self.assertEqual(db_genres.filter(name="Sci-fi").count(), 1) + + def test_get_invalid_genre(self): + response = self.client.get("/api/cinema/genres/1001/") + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + + def test_put_genre(self): + response = self.client.put( + "/api/cinema/genres/1/", + { + "name": "Sci-fi", + }, + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_delete_genre(self): + response = self.client.delete( + "/api/cinema/genres/1/", + ) + db_genres_id_1 = Genre.objects.filter(id=1) + self.assertEqual(db_genres_id_1.count(), 0) + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) + + def test_delete_invalid_genre(self): + response = self.client.delete( + "/api/cinema/genres/1000/", + ) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) diff --git a/cinema/tests/test_movie_api.py b/cinema/tests/test_movie_api.py index 9d6b76bf..9e8cb0aa 100644 --- a/cinema/tests/test_movie_api.py +++ b/cinema/tests/test_movie_api.py @@ -1,127 +1,127 @@ -from django.test import TestCase - -from rest_framework.test import APIClient -from rest_framework import status - -from cinema.models import Movie, Genre, Actor - - -class MovieApiTests(TestCase): - def setUp(self): - self.client = APIClient() - drama = Genre.objects.create( - name="Drama", - ) - comedy = Genre.objects.create( - name="Comedy", - ) - actress = Actor.objects.create(first_name="Kate", last_name="Winslet") - movie = Movie.objects.create( - title="Titanic", - description="Titanic description", - duration=123, - ) - movie.genres.add(drama) - movie.genres.add(comedy) - movie.actors.add(actress) - - def test_get_movies(self): - movies = self.client.get("/api/cinema/movies/") - titanic = { - "title": "Titanic", - "description": "Titanic description", - "duration": 123, - "genres": ["Drama", "Comedy"], - "actors": ["Kate Winslet"], - } - print(movies.data) - self.assertEqual(movies.status_code, status.HTTP_200_OK) - for field in titanic: - self.assertEqual(movies.data[0][field], titanic[field]) - - def test_post_movies(self): - movies = self.client.post( - "/api/cinema/movies/", - { - "title": "Superman", - "description": "Superman description", - "duration": 123, - "actors": [1], - "genres": [1, 2], - }, - ) - db_movies = Movie.objects.all() - self.assertEqual(movies.status_code, status.HTTP_201_CREATED) - self.assertEqual(db_movies.count(), 2) - self.assertEqual(db_movies.filter(title="Superman").count(), 1) - - def test_post_invalid_movies(self): - movies = self.client.post( - "/api/cinema/movies/", - { - "title": "Superman", - "description": "Superman description", - "duration": 123, - "actors": [ - { - "id": 3, - } - ], - }, - ) - superman_movies = Movie.objects.filter(title="Superman") - self.assertEqual(movies.status_code, status.HTTP_400_BAD_REQUEST) - self.assertEqual(superman_movies.count(), 0) - - def test_get_movie(self): - response = self.client.get("/api/cinema/movies/1/") - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data["title"], "Titanic") - self.assertEqual(response.data["description"], "Titanic description") - self.assertEqual(response.data["duration"], 123) - self.assertEqual(response.data["genres"][0]["name"], "Drama") - self.assertEqual(response.data["genres"][1]["name"], "Comedy") - self.assertEqual(response.data["actors"][0]["first_name"], "Kate") - self.assertEqual(response.data["actors"][0]["last_name"], "Winslet") - self.assertEqual( - response.data["actors"][0]["full_name"], "Kate Winslet" - ) - - def test_get_invalid_movie(self): - response = self.client.get("/api/cinema/movies/100/") - self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) - - def test_put_movie(self): - self.client.put( - "/api/cinema/movies/1/", - { - "title": "Watchman", - "description": "Watchman description", - "duration": 321, - "genres": [1, 2], - "actors": [1], - }, - ) - db_movie = Movie.objects.get(id=1) - self.assertEqual( - [db_movie.title, db_movie.description], - [ - "Watchman", - "Watchman description", - ], - ) - self.assertEqual(db_movie.title, "Watchman") - - def test_delete_movie(self): - response = self.client.delete( - "/api/cinema/movies/1/", - ) - db_movies_id_1 = Movie.objects.filter(id=1) - self.assertEqual(db_movies_id_1.count(), 0) - self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) - - def test_delete_invalid_movie(self): - response = self.client.delete( - "/api/cinema/movies/1000/", - ) - self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) +from django.test import TestCase + +from rest_framework.test import APIClient +from rest_framework import status + +from cinema.models import Movie, Genre, Actor + + +class MovieApiTests(TestCase): + def setUp(self): + self.client = APIClient() + drama = Genre.objects.create( + name="Drama", + ) + comedy = Genre.objects.create( + name="Comedy", + ) + actress = Actor.objects.create(first_name="Kate", last_name="Winslet") + movie = Movie.objects.create( + title="Titanic", + description="Titanic description", + duration=123, + ) + movie.genres.add(drama) + movie.genres.add(comedy) + movie.actors.add(actress) + + def test_get_movies(self): + movies = self.client.get("/api/cinema/movies/") + titanic = { + "title": "Titanic", + "description": "Titanic description", + "duration": 123, + "genres": ["Drama", "Comedy"], + "actors": ["Kate Winslet"], + } + print(movies.data) + self.assertEqual(movies.status_code, status.HTTP_200_OK) + for field in titanic: + self.assertEqual(movies.data[0][field], titanic[field]) + + def test_post_movies(self): + movies = self.client.post( + "/api/cinema/movies/", + { + "title": "Superman", + "description": "Superman description", + "duration": 123, + "actors": [1], + "genres": [1, 2], + }, + ) + db_movies = Movie.objects.all() + self.assertEqual(movies.status_code, status.HTTP_201_CREATED) + self.assertEqual(db_movies.count(), 2) + self.assertEqual(db_movies.filter(title="Superman").count(), 1) + + def test_post_invalid_movies(self): + movies = self.client.post( + "/api/cinema/movies/", + { + "title": "Superman", + "description": "Superman description", + "duration": 123, + "actors": [ + { + "id": 3, + } + ], + }, + ) + superman_movies = Movie.objects.filter(title="Superman") + self.assertEqual(movies.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(superman_movies.count(), 0) + + def test_get_movie(self): + response = self.client.get("/api/cinema/movies/1/") + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data["title"], "Titanic") + self.assertEqual(response.data["description"], "Titanic description") + self.assertEqual(response.data["duration"], 123) + self.assertEqual(response.data["genres"][0]["name"], "Drama") + self.assertEqual(response.data["genres"][1]["name"], "Comedy") + self.assertEqual(response.data["actors"][0]["first_name"], "Kate") + self.assertEqual(response.data["actors"][0]["last_name"], "Winslet") + self.assertEqual( + response.data["actors"][0]["full_name"], "Kate Winslet" + ) + + def test_get_invalid_movie(self): + response = self.client.get("/api/cinema/movies/100/") + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + + def test_put_movie(self): + self.client.put( + "/api/cinema/movies/1/", + { + "title": "Watchman", + "description": "Watchman description", + "duration": 321, + "genres": [1, 2], + "actors": [1], + }, + ) + db_movie = Movie.objects.get(id=1) + self.assertEqual( + [db_movie.title, db_movie.description], + [ + "Watchman", + "Watchman description", + ], + ) + self.assertEqual(db_movie.title, "Watchman") + + def test_delete_movie(self): + response = self.client.delete( + "/api/cinema/movies/1/", + ) + db_movies_id_1 = Movie.objects.filter(id=1) + self.assertEqual(db_movies_id_1.count(), 0) + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) + + def test_delete_invalid_movie(self): + response = self.client.delete( + "/api/cinema/movies/1000/", + ) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) diff --git a/cinema/tests/test_movie_session_api.py b/cinema/tests/test_movie_session_api.py index cbd02713..4f7ce7fc 100644 --- a/cinema/tests/test_movie_session_api.py +++ b/cinema/tests/test_movie_session_api.py @@ -1,79 +1,79 @@ -import datetime - -from django.test import TestCase - -from rest_framework.test import APIClient -from rest_framework import status - -from cinema.models import Movie, Genre, Actor, MovieSession, CinemaHall - - -class MovieSessionApiTests(TestCase): - def setUp(self): - self.client = APIClient() - drama = Genre.objects.create( - name="Drama", - ) - comedy = Genre.objects.create( - name="Comedy", - ) - actress = Actor.objects.create(first_name="Kate", last_name="Winslet") - self.movie = Movie.objects.create( - title="Titanic", - description="Titanic description", - duration=123, - ) - self.movie.genres.add(drama) - self.movie.genres.add(comedy) - self.movie.actors.add(actress) - self.cinema_hall = CinemaHall.objects.create( - name="White", - rows=10, - seats_in_row=14, - ) - self.movie_session = MovieSession.objects.create( - movie=self.movie, - cinema_hall=self.cinema_hall, - show_time=datetime.datetime.now(), - ) - - def test_get_movie_sessions(self): - movie_sessions = self.client.get("/api/cinema/movie_sessions/") - movie_session = { - "movie_title": "Titanic", - "cinema_hall_name": "White", - "cinema_hall_capacity": 140, - } - self.assertEqual(movie_sessions.status_code, status.HTTP_200_OK) - for field in movie_session: - self.assertEqual( - movie_sessions.data[0][field], movie_session[field] - ) - - def test_post_movie_session(self): - movies = self.client.post( - "/api/cinema/movie_sessions/", - { - "movie": 1, - "cinema_hall": 1, - "show_time": datetime.datetime.now(), - }, - ) - movie_sessions = MovieSession.objects.all() - self.assertEqual(movies.status_code, status.HTTP_201_CREATED) - self.assertEqual(movie_sessions.count(), 2) - - def test_get_movie_session(self): - response = self.client.get("/api/cinema/movie_sessions/1/") - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data["movie"]["title"], "Titanic") - self.assertEqual( - response.data["movie"]["description"], "Titanic description" - ) - self.assertEqual(response.data["movie"]["duration"], 123) - self.assertEqual(response.data["movie"]["genres"], ["Drama", "Comedy"]) - self.assertEqual(response.data["movie"]["actors"], ["Kate Winslet"]) - self.assertEqual(response.data["cinema_hall"]["capacity"], 140) - self.assertEqual(response.data["cinema_hall"]["rows"], 10) - self.assertEqual(response.data["cinema_hall"]["seats_in_row"], 14) - self.assertEqual(response.data["cinema_hall"]["name"], "White") +import datetime + +from django.test import TestCase + +from rest_framework.test import APIClient +from rest_framework import status + +from cinema.models import Movie, Genre, Actor, MovieSession, CinemaHall + + +class MovieSessionApiTests(TestCase): + def setUp(self): + self.client = APIClient() + drama = Genre.objects.create( + name="Drama", + ) + comedy = Genre.objects.create( + name="Comedy", + ) + actress = Actor.objects.create(first_name="Kate", last_name="Winslet") + self.movie = Movie.objects.create( + title="Titanic", + description="Titanic description", + duration=123, + ) + self.movie.genres.add(drama) + self.movie.genres.add(comedy) + self.movie.actors.add(actress) + self.cinema_hall = CinemaHall.objects.create( + name="White", + rows=10, + seats_in_row=14, + ) + self.movie_session = MovieSession.objects.create( + movie=self.movie, + cinema_hall=self.cinema_hall, + show_time=datetime.datetime.now(), + ) + + def test_get_movie_sessions(self): + movie_sessions = self.client.get("/api/cinema/movie_sessions/") + movie_session = { + "movie_title": "Titanic", + "cinema_hall_name": "White", + "cinema_hall_capacity": 140, + } + self.assertEqual(movie_sessions.status_code, status.HTTP_200_OK) + for field in movie_session: + self.assertEqual( + movie_sessions.data[0][field], movie_session[field] + ) + + def test_post_movie_session(self): + movies = self.client.post( + "/api/cinema/movie_sessions/", + { + "movie": 1, + "cinema_hall": 1, + "show_time": datetime.datetime.now(), + }, + ) + movie_sessions = MovieSession.objects.all() + self.assertEqual(movies.status_code, status.HTTP_201_CREATED) + self.assertEqual(movie_sessions.count(), 2) + + def test_get_movie_session(self): + response = self.client.get("/api/cinema/movie_sessions/1/") + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data["movie"]["title"], "Titanic") + self.assertEqual( + response.data["movie"]["description"], "Titanic description" + ) + self.assertEqual(response.data["movie"]["duration"], 123) + self.assertEqual(response.data["movie"]["genres"], ["Drama", "Comedy"]) + self.assertEqual(response.data["movie"]["actors"], ["Kate Winslet"]) + self.assertEqual(response.data["cinema_hall"]["capacity"], 140) + self.assertEqual(response.data["cinema_hall"]["rows"], 10) + self.assertEqual(response.data["cinema_hall"]["seats_in_row"], 14) + self.assertEqual(response.data["cinema_hall"]["name"], "White") diff --git a/cinema/urls.py b/cinema/urls.py index 420f8e8c..1b008c8b 100644 --- a/cinema/urls.py +++ b/cinema/urls.py @@ -1 +1,14 @@ -# write urls here +from django.urls import path, include +from rest_framework.routers import DefaultRouter +from cinema.views import GenreViewSet, ActorViewSet, CinemaHallViewSet, MovieViewSet, MovieSessionViewSet + +router = DefaultRouter() +router.register("genres", GenreViewSet) +router.register("actors", ActorViewSet) +router.register("cinema_halls", CinemaHallViewSet) +router.register("movies", MovieViewSet) +router.register("movie_sessions", MovieSessionViewSet) + +urlpatterns = [ + path("", include(router.urls)), +] \ No newline at end of file diff --git a/cinema/views.py b/cinema/views.py index ae87bfde..2ac55c40 100644 --- a/cinema/views.py +++ b/cinema/views.py @@ -1 +1,30 @@ -# write views here +from rest_framework import viewsets + +from cinema.models import Genre, Actor, Movie, CinemaHall, MovieSession +from cinema.serializers import GenreSerializer, ActorSerializer, CinemaHallSerializer, MovieSerializer, \ + MovieSessionSerializer + + +class GenreViewSet(viewsets.ModelViewSet): + queryset = Genre.objects.all() + serializer_class = GenreSerializer + + +class ActorViewSet(viewsets.ModelViewSet): + queryset = Actor.objects.all() + serializer_class = ActorSerializer + + +class CinemaHallViewSet(viewsets.ModelViewSet): + queryset = CinemaHall.objects.all() + serializer_class = CinemaHallSerializer + + +class MovieViewSet(viewsets.ModelViewSet): + queryset = Movie.objects.all() + serializer_class = MovieSerializer + + +class MovieSessionViewSet(viewsets.ModelViewSet): + queryset = MovieSession.objects.all() + serializer_class = MovieSessionSerializer \ No newline at end of file diff --git a/cinema_service/asgi.py b/cinema_service/asgi.py index 40d094eb..38e7b81c 100644 --- a/cinema_service/asgi.py +++ b/cinema_service/asgi.py @@ -1,16 +1,16 @@ -""" -ASGI config for cinema_service project. - -It exposes the ASGI callable as a module-level variable named ``application``. - -For more information on this file, see -https://docs.djangoproject.com/en/4.0/howto/deployment/asgi/ -""" - -import os - -from django.core.asgi import get_asgi_application - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cinema_service.settings") - -application = get_asgi_application() +""" +ASGI config for cinema_service project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.0/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cinema_service.settings") + +application = get_asgi_application() diff --git a/cinema_service/settings.py b/cinema_service/settings.py index 4b981921..cf1be309 100644 --- a/cinema_service/settings.py +++ b/cinema_service/settings.py @@ -1,133 +1,133 @@ -""" -Django settings for cinema_service project. - -Generated by 'django-admin startproject' using Django 4.0.4. - -For more information on this file, see -https://docs.djangoproject.com/en/4.0/topics/settings/ - -For the full list of settings and their values, see -https://docs.djangoproject.com/en/4.0/ref/settings/ -""" - -from pathlib import Path - -# Build paths inside the project like this: BASE_DIR / 'subdir'. -BASE_DIR = Path(__file__).resolve().parent.parent - - -# Quick-start development settings - unsuitable for production -# See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/ - -# SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = ( - "django-insecure-6vubhk2$++agnctay_4pxy_8cq)mosmn(*-#2b^v4cgsh-^!i3" -) - -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True - -ALLOWED_HOSTS = [] - - -# Application definition - -INSTALLED_APPS = [ - "django.contrib.admin", - "django.contrib.auth", - "django.contrib.contenttypes", - "django.contrib.sessions", - "django.contrib.messages", - "django.contrib.staticfiles", - "rest_framework", - "cinema", - "user", -] - -MIDDLEWARE = [ - "django.middleware.security.SecurityMiddleware", - "django.contrib.sessions.middleware.SessionMiddleware", - "django.middleware.common.CommonMiddleware", - "django.middleware.csrf.CsrfViewMiddleware", - "django.contrib.auth.middleware.AuthenticationMiddleware", - "django.contrib.messages.middleware.MessageMiddleware", - "django.middleware.clickjacking.XFrameOptionsMiddleware", -] - -ROOT_URLCONF = "cinema_service.urls" - -TEMPLATES = [ - { - "BACKEND": "django.template.backends.django.DjangoTemplates", - "DIRS": [], - "APP_DIRS": True, - "OPTIONS": { - "context_processors": [ - "django.template.context_processors.debug", - "django.template.context_processors.request", - "django.contrib.auth.context_processors.auth", - "django.contrib.messages.context_processors.messages", - ], - }, - }, -] - -WSGI_APPLICATION = "cinema_service.wsgi.application" - - -# Database -# https://docs.djangoproject.com/en/4.0/ref/settings/#databases - -DATABASES = { - "default": { - "ENGINE": "django.db.backends.sqlite3", - "NAME": BASE_DIR / "db.sqlite3", - } -} - - -# Password validation -# https://docs.djangoproject.com/en/4.0/ref/settings/#auth-password-validators - -AUTH_PASSWORD_VALIDATORS = [ - { - "NAME": "django.contrib.auth.password_validation." - "UserAttributeSimilarityValidator", - }, - { - "NAME": "django.contrib.auth.password_validation." - "MinimumLengthValidator", - }, - { - "NAME": "django.contrib.auth.password_validation." - "CommonPasswordValidator", - }, - { - "NAME": "django.contrib.auth.password_validation." - "NumericPasswordValidator", - }, -] - -AUTH_USER_MODEL = "user.User" - -# Internationalization -# https://docs.djangoproject.com/en/4.0/topics/i18n/ - -LANGUAGE_CODE = "en-us" - -TIME_ZONE = "UTC" - -USE_I18N = True - -USE_TZ = True - - -# Static files (CSS, JavaScript, Images) -# https://docs.djangoproject.com/en/4.0/howto/static-files/ - -STATIC_URL = "static/" - -# Default primary key field type -# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field - -DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" +""" +Django settings for cinema_service project. + +Generated by 'django-admin startproject' using Django 4.0.4. + +For more information on this file, see +https://docs.djangoproject.com/en/4.0/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/4.0/ref/settings/ +""" + +from pathlib import Path + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = ( + "django-insecure-6vubhk2$++agnctay_4pxy_8cq)mosmn(*-#2b^v4cgsh-^!i3" +) + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "rest_framework", + "cinema", + "user", +] + +MIDDLEWARE = [ + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", +] + +ROOT_URLCONF = "cinema_service.urls" + +TEMPLATES = [ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + ], + }, + }, +] + +WSGI_APPLICATION = "cinema_service.wsgi.application" + + +# Database +# https://docs.djangoproject.com/en/4.0/ref/settings/#databases + +DATABASES = { + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": BASE_DIR / "db.sqlite3", + } +} + + +# Password validation +# https://docs.djangoproject.com/en/4.0/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + "NAME": "django.contrib.auth.password_validation." + "UserAttributeSimilarityValidator", + }, + { + "NAME": "django.contrib.auth.password_validation." + "MinimumLengthValidator", + }, + { + "NAME": "django.contrib.auth.password_validation." + "CommonPasswordValidator", + }, + { + "NAME": "django.contrib.auth.password_validation." + "NumericPasswordValidator", + }, +] + +AUTH_USER_MODEL = "user.User" + +# Internationalization +# https://docs.djangoproject.com/en/4.0/topics/i18n/ + +LANGUAGE_CODE = "en-us" + +TIME_ZONE = "UTC" + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/4.0/howto/static-files/ + +STATIC_URL = "static/" + +# Default primary key field type +# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" diff --git a/cinema_service/urls.py b/cinema_service/urls.py index 083932c6..ab64cb7c 100644 --- a/cinema_service/urls.py +++ b/cinema_service/urls.py @@ -1,6 +1,7 @@ -from django.contrib import admin -from django.urls import path - -urlpatterns = [ - path("admin/", admin.site.urls), -] +from django.contrib import admin +from django.urls import path, include + +urlpatterns = [ + path("admin/", admin.site.urls), + path("api/cinema/", include("cinema.urls")), +] diff --git a/cinema_service/wsgi.py b/cinema_service/wsgi.py index 7cc91620..0e6a8483 100644 --- a/cinema_service/wsgi.py +++ b/cinema_service/wsgi.py @@ -1,16 +1,16 @@ -""" -WSGI config for cinema_service project. - -It exposes the WSGI callable as a module-level variable named ``application``. - -For more information on this file, see -https://docs.djangoproject.com/en/4.0/howto/deployment/wsgi/ -""" - -import os - -from django.core.wsgi import get_wsgi_application - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cinema_service.settings") - -application = get_wsgi_application() +""" +WSGI config for cinema_service project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.0/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cinema_service.settings") + +application = get_wsgi_application() diff --git a/cinema_service_db_data.json b/cinema_service_db_data.json index 5bd3764e..4c504fea 100644 --- a/cinema_service_db_data.json +++ b/cinema_service_db_data.json @@ -1,553 +1,553 @@ -[ - { - "model": "cinema.cinemahall", - "pk": 1, - "fields": { - "name": "Ricciotto Canudo", - "rows": 25, - "seats_in_row": 30 - } - }, - { - "model": "cinema.cinemahall", - "pk": 2, - "fields": { - "name": "Robin Wood", - "rows": 24, - "seats_in_row": 18 - } - }, - { - "model": "cinema.cinemahall", - "pk": 3, - "fields": { - "name": "Peter Wollen", - "rows": 30, - "seats_in_row": 20 - } - }, - { - "model": "cinema.cinemahall", - "pk": 4, - "fields": { - "name": "Jean Mitry", - "rows": 14, - "seats_in_row": 8 - } - }, - { - "model": "cinema.genre", - "pk": 1, - "fields": { - "name": "Crime" - } - }, - { - "model": "cinema.genre", - "pk": 2, - "fields": { - "name": "Drama" - } - }, - { - "model": "cinema.genre", - "pk": 3, - "fields": { - "name": "Thriller" - } - }, - { - "model": "cinema.genre", - "pk": 4, - "fields": { - "name": "Action" - } - }, - { - "model": "cinema.genre", - "pk": 5, - "fields": { - "name": "Adventure" - } - }, - { - "model": "cinema.genre", - "pk": 6, - "fields": { - "name": "Sci-Fi" - } - }, - { - "model": "cinema.genre", - "pk": 7, - "fields": { - "name": "Mystery" - } - }, - { - "model": "cinema.actor", - "pk": 1, - "fields": { - "first_name": "Jack", - "last_name": "Nicholson" - } - }, - { - "model": "cinema.actor", - "pk": 2, - "fields": { - "first_name": "Leonardo", - "last_name": "DiCaprio" - } - }, - { - "model": "cinema.actor", - "pk": 3, - "fields": { - "first_name": "Matt", - "last_name": "Damon" - } - }, - { - "model": "cinema.actor", - "pk": 4, - "fields": { - "first_name": "Joseph", - "last_name": "Gordon-Levitt" - } - }, - { - "model": "cinema.actor", - "pk": 5, - "fields": { - "first_name": "Elliot", - "last_name": "Page" - } - }, - { - "model": "cinema.actor", - "pk": 6, - "fields": { - "first_name": "Bruce", - "last_name": "Willis" - } - }, - { - "model": "cinema.actor", - "pk": 7, - "fields": { - "first_name": "Emily", - "last_name": "Blunt" - } - }, - { - "model": "cinema.actor", - "pk": 8, - "fields": { - "first_name": "Samuel", - "last_name": "Jackson" - } - }, - { - "model": "cinema.actor", - "pk": 9, - "fields": { - "first_name": "Robin", - "last_name": "Wright" - } - }, - { - "model": "cinema.movie", - "pk": 1, - "fields": { - "title": "The Departed", - "description": "An undercover cop and a mole in the police attempt to identify each other while infiltrating an Irishgang in South Boston.", - "duration": 151, - "genres": [ - 1, - 2, - 3 - ], - "actors": [ - 1, - 2, - 3 - ] - } - }, - { - "model": "cinema.movie", - "pk": 2, - "fields": { - "title": "Inception", - "description": "A thief who steals corporate secrets through the use of dream-sharing technology is given the inverse task of planting an idea into the mind of a C.E.O.", - "duration": 148, - "genres": [ - 4, - 5, - 6 - ], - "actors": [ - 2, - 4, - 5 - ] - } - }, - { - "model": "cinema.movie", - "pk": 3, - "fields": { - "title": "Looper", - "description": "In 2074, when the mob wants to get rid of someone, the target is sent into the past, where a hired gun awaits - someone like Joe - who one day learns the mob wants to 'close the loop' by sending back Joe's future self for assassination.", - "duration": 119, - "genres": [ - 2, - 4, - 6 - ], - "actors": [ - 4, - 6, - 7 - ] - } - }, - { - "model": "cinema.movie", - "pk": 4, - "fields": { - "title": "Unbreakable", - "description": "A man learns something extraordinary about himself after a devastating accident.", - "duration": 106, - "genres": [ - 2, - 6, - 7 - ], - "actors": [ - 6, - 8, - 9 - ] - } - }, - { - "model": "cinema.moviesession", - "pk": 1, - "fields": { - "show_time": "2024-10-08T13:00:00Z", - "movie": 1, - "cinema_hall": 1 - } - }, - { - "model": "cinema.moviesession", - "pk": 2, - "fields": { - "show_time": "2024-10-09T13:00:00Z", - "movie": 2, - "cinema_hall": 2 - } - }, - { - "model": "cinema.moviesession", - "pk": 3, - "fields": { - "show_time": "2024-10-10T13:00:00Z", - "movie": 3, - "cinema_hall": 3 - } - }, - { - "model": "cinema.moviesession", - "pk": 4, - "fields": { - "show_time": "2024-10-11T13:00:00Z", - "movie": 4, - "cinema_hall": 4 - } - }, - { - "model": "cinema.moviesession", - "pk": 5, - "fields": { - "show_time": "2024-10-12T13:00:00Z", - "movie": 4, - "cinema_hall": 1 - } - }, - { - "model": "cinema.moviesession", - "pk": 6, - "fields": { - "show_time": "2024-10-13T13:00:00Z", - "movie": 3, - "cinema_hall": 2 - } - }, - { - "model": "cinema.moviesession", - "pk": 7, - "fields": { - "show_time":"2024-10-14T13:00:00Z", - "movie": 1, - "cinema_hall": 3 - } - }, - { - "model": "cinema.moviesession", - "pk": 8, - "fields": { - "show_time": "2024-10-15T13:00:00Z", - "movie": 2, - "cinema_hall": 4 - } - }, - { - "model": "cinema.order", - "pk": 1, - "fields": { - "created_at": "2022-08-09T09:06:18.876Z", - "user": 1 - } - }, - { - "model": "cinema.order", - "pk": 2, - "fields": { - "created_at": "2022-08-09T09:06:18.876Z", - "user": 2 - } - }, - { - "model": "cinema.order", - "pk": 3, - "fields": { - "created_at": "2022-08-09T09:06:18.876Z", - "user": 1 - } - }, - { - "model": "cinema.order", - "pk": 4, - "fields": { - "created_at": "2022-08-09T09:06:18.876Z", - "user": 3 - } - }, - { - "model": "cinema.ticket", - "pk": 1, - "fields": { - "movie_session": 1, - "order": 1, - "row": 1, - "seat": 1 - } - }, - { - "model": "cinema.ticket", - "pk": 2, - "fields": { - "movie_session": 1, - "order": 1, - "row": 2, - "seat": 4 - } - }, - { - "model": "cinema.ticket", - "pk": 3, - "fields": { - "movie_session": 2, - "order": 1, - "row": 3, - "seat": 3 - } - }, - { - "model": "cinema.ticket", - "pk": 4, - "fields": { - "movie_session": 2, - "order": 1, - "row": 4, - "seat": 3 - } - }, - { - "model": "cinema.ticket", - "pk": 5, - "fields": { - "movie_session": 3, - "order": 1, - "row": 5, - "seat": 1 - } - }, - { - "model": "cinema.ticket", - "pk": 6, - "fields": { - "movie_session": 4, - "order": 1, - "row": 6, - "seat": 2 - } - }, - { - "model": "cinema.ticket", - "pk": 7, - "fields": { - "movie_session": 5, - "order": 1, - "row": 7, - "seat": 3 - } - }, - { - "model": "cinema.ticket", - "pk": 8, - "fields": { - "movie_session": 5, - "order": 2, - "row": 8, - "seat": 4 - } - }, - { - "model": "cinema.ticket", - "pk": 9, - "fields": { - "movie_session": 5, - "order": 2, - "row": 1, - "seat": 5 - } - }, - { - "model": "cinema.ticket", - "pk": 10, - "fields": { - "movie_session": 6, - "order": 2, - "row": 1, - "seat": 6 - } - }, - { - "model": "cinema.ticket", - "pk": 11, - "fields": { - "movie_session": 7, - "order": 3, - "row": 4, - "seat": 7 - } - }, - { - "model": "cinema.ticket", - "pk": 12, - "fields": { - "movie_session": 8, - "order": 3, - "row": 3, - "seat": 7 - } - }, - { - "model": "cinema.ticket", - "pk": 13, - "fields": { - "movie_session": 8, - "order": 3, - "row": 5, - "seat": 4 - } - }, - { - "model": "cinema.ticket", - "pk": 14, - "fields": { - "movie_session": 8, - "order": 4, - "row": 4, - "seat": 4 - } - }, - { - "model": "cinema.ticket", - "pk": 15, - "fields": { - "movie_session": 1, - "order": 4, - "row": 2, - "seat": 3 - } - }, - { - "model": "cinema.ticket", - "pk": 16, - "fields": { - "movie_session": 2, - "order": 4, - "row": 5, - "seat": 3 - } - }, - { - "model": "user.user", - "pk": 1, - "fields": { - "password": "pbkdf2_sha256$320000$oZqdjfUqKC500V7kk3kMmb$TBVlOMhfJxWrxbUnNpWZK0+rYM242g7do/YM5tkhn+M=", - "last_login": null, - "is_superuser": true, - "username": "admin.user", - "first_name": "Admin", - "last_name": "User", - "email": "admin.user@cinema.com", - "is_staff": true, - "is_active": true, - "date_joined": "2022-08-09T09:06:18.876Z", - "groups": [], - "user_permissions": [] - } - }, - { - "model": "user.user", - "pk": 2, - "fields": { - "password": "pbkdf2_sha256$320000$73Z1Y57bcoscZ37s9rE9v0$4SEQ0TtXwJKzO5/CRdFSrTifatiPjkZ38gM2H8Kqsdg=", - "last_login": null, - "is_superuser": false, - "username": "ivan.khripko", - "first_name": "Ivan", - "last_name": "Khripko", - "email": "ivan.khripko@cinema.com", - "is_staff": false, - "is_active": true, - "date_joined": "2022-08-09T09:06:18.876Z", - "groups": [], - "user_permissions": [] - } - }, - { - "model": "user.user", - "pk": 3, - "fields": { - "password": "pbkdf2_sha256$320000$QtPol3T7x9quBj4BnbnVwW$UwT4kihkRfSvQEWEeuqVKwMgis2ikKVZfJDBcQMvOKY=", - "last_login": null, - "is_superuser": false, - "username": "mykola.hmara", - "first_name": "Mykola", - "last_name": "Hmara", - "email": "mykola.hmara@cinema.com", - "is_staff": false, - "is_active": true, - "date_joined": "2022-08-09T09:06:18.876Z", - "groups": [], - "user_permissions": [] - } - } -] +[ + { + "model": "cinema.cinemahall", + "pk": 1, + "fields": { + "name": "Ricciotto Canudo", + "rows": 25, + "seats_in_row": 30 + } + }, + { + "model": "cinema.cinemahall", + "pk": 2, + "fields": { + "name": "Robin Wood", + "rows": 24, + "seats_in_row": 18 + } + }, + { + "model": "cinema.cinemahall", + "pk": 3, + "fields": { + "name": "Peter Wollen", + "rows": 30, + "seats_in_row": 20 + } + }, + { + "model": "cinema.cinemahall", + "pk": 4, + "fields": { + "name": "Jean Mitry", + "rows": 14, + "seats_in_row": 8 + } + }, + { + "model": "cinema.genre", + "pk": 1, + "fields": { + "name": "Crime" + } + }, + { + "model": "cinema.genre", + "pk": 2, + "fields": { + "name": "Drama" + } + }, + { + "model": "cinema.genre", + "pk": 3, + "fields": { + "name": "Thriller" + } + }, + { + "model": "cinema.genre", + "pk": 4, + "fields": { + "name": "Action" + } + }, + { + "model": "cinema.genre", + "pk": 5, + "fields": { + "name": "Adventure" + } + }, + { + "model": "cinema.genre", + "pk": 6, + "fields": { + "name": "Sci-Fi" + } + }, + { + "model": "cinema.genre", + "pk": 7, + "fields": { + "name": "Mystery" + } + }, + { + "model": "cinema.actor", + "pk": 1, + "fields": { + "first_name": "Jack", + "last_name": "Nicholson" + } + }, + { + "model": "cinema.actor", + "pk": 2, + "fields": { + "first_name": "Leonardo", + "last_name": "DiCaprio" + } + }, + { + "model": "cinema.actor", + "pk": 3, + "fields": { + "first_name": "Matt", + "last_name": "Damon" + } + }, + { + "model": "cinema.actor", + "pk": 4, + "fields": { + "first_name": "Joseph", + "last_name": "Gordon-Levitt" + } + }, + { + "model": "cinema.actor", + "pk": 5, + "fields": { + "first_name": "Elliot", + "last_name": "Page" + } + }, + { + "model": "cinema.actor", + "pk": 6, + "fields": { + "first_name": "Bruce", + "last_name": "Willis" + } + }, + { + "model": "cinema.actor", + "pk": 7, + "fields": { + "first_name": "Emily", + "last_name": "Blunt" + } + }, + { + "model": "cinema.actor", + "pk": 8, + "fields": { + "first_name": "Samuel", + "last_name": "Jackson" + } + }, + { + "model": "cinema.actor", + "pk": 9, + "fields": { + "first_name": "Robin", + "last_name": "Wright" + } + }, + { + "model": "cinema.movie", + "pk": 1, + "fields": { + "title": "The Departed", + "description": "An undercover cop and a mole in the police attempt to identify each other while infiltrating an Irishgang in South Boston.", + "duration": 151, + "genres": [ + 1, + 2, + 3 + ], + "actors": [ + 1, + 2, + 3 + ] + } + }, + { + "model": "cinema.movie", + "pk": 2, + "fields": { + "title": "Inception", + "description": "A thief who steals corporate secrets through the use of dream-sharing technology is given the inverse task of planting an idea into the mind of a C.E.O.", + "duration": 148, + "genres": [ + 4, + 5, + 6 + ], + "actors": [ + 2, + 4, + 5 + ] + } + }, + { + "model": "cinema.movie", + "pk": 3, + "fields": { + "title": "Looper", + "description": "In 2074, when the mob wants to get rid of someone, the target is sent into the past, where a hired gun awaits - someone like Joe - who one day learns the mob wants to 'close the loop' by sending back Joe's future self for assassination.", + "duration": 119, + "genres": [ + 2, + 4, + 6 + ], + "actors": [ + 4, + 6, + 7 + ] + } + }, + { + "model": "cinema.movie", + "pk": 4, + "fields": { + "title": "Unbreakable", + "description": "A man learns something extraordinary about himself after a devastating accident.", + "duration": 106, + "genres": [ + 2, + 6, + 7 + ], + "actors": [ + 6, + 8, + 9 + ] + } + }, + { + "model": "cinema.moviesession", + "pk": 1, + "fields": { + "show_time": "2024-10-08T13:00:00Z", + "movie": 1, + "cinema_hall": 1 + } + }, + { + "model": "cinema.moviesession", + "pk": 2, + "fields": { + "show_time": "2024-10-09T13:00:00Z", + "movie": 2, + "cinema_hall": 2 + } + }, + { + "model": "cinema.moviesession", + "pk": 3, + "fields": { + "show_time": "2024-10-10T13:00:00Z", + "movie": 3, + "cinema_hall": 3 + } + }, + { + "model": "cinema.moviesession", + "pk": 4, + "fields": { + "show_time": "2024-10-11T13:00:00Z", + "movie": 4, + "cinema_hall": 4 + } + }, + { + "model": "cinema.moviesession", + "pk": 5, + "fields": { + "show_time": "2024-10-12T13:00:00Z", + "movie": 4, + "cinema_hall": 1 + } + }, + { + "model": "cinema.moviesession", + "pk": 6, + "fields": { + "show_time": "2024-10-13T13:00:00Z", + "movie": 3, + "cinema_hall": 2 + } + }, + { + "model": "cinema.moviesession", + "pk": 7, + "fields": { + "show_time":"2024-10-14T13:00:00Z", + "movie": 1, + "cinema_hall": 3 + } + }, + { + "model": "cinema.moviesession", + "pk": 8, + "fields": { + "show_time": "2024-10-15T13:00:00Z", + "movie": 2, + "cinema_hall": 4 + } + }, + { + "model": "cinema.order", + "pk": 1, + "fields": { + "created_at": "2022-08-09T09:06:18.876Z", + "user": 1 + } + }, + { + "model": "cinema.order", + "pk": 2, + "fields": { + "created_at": "2022-08-09T09:06:18.876Z", + "user": 2 + } + }, + { + "model": "cinema.order", + "pk": 3, + "fields": { + "created_at": "2022-08-09T09:06:18.876Z", + "user": 1 + } + }, + { + "model": "cinema.order", + "pk": 4, + "fields": { + "created_at": "2022-08-09T09:06:18.876Z", + "user": 3 + } + }, + { + "model": "cinema.ticket", + "pk": 1, + "fields": { + "movie_session": 1, + "order": 1, + "row": 1, + "seat": 1 + } + }, + { + "model": "cinema.ticket", + "pk": 2, + "fields": { + "movie_session": 1, + "order": 1, + "row": 2, + "seat": 4 + } + }, + { + "model": "cinema.ticket", + "pk": 3, + "fields": { + "movie_session": 2, + "order": 1, + "row": 3, + "seat": 3 + } + }, + { + "model": "cinema.ticket", + "pk": 4, + "fields": { + "movie_session": 2, + "order": 1, + "row": 4, + "seat": 3 + } + }, + { + "model": "cinema.ticket", + "pk": 5, + "fields": { + "movie_session": 3, + "order": 1, + "row": 5, + "seat": 1 + } + }, + { + "model": "cinema.ticket", + "pk": 6, + "fields": { + "movie_session": 4, + "order": 1, + "row": 6, + "seat": 2 + } + }, + { + "model": "cinema.ticket", + "pk": 7, + "fields": { + "movie_session": 5, + "order": 1, + "row": 7, + "seat": 3 + } + }, + { + "model": "cinema.ticket", + "pk": 8, + "fields": { + "movie_session": 5, + "order": 2, + "row": 8, + "seat": 4 + } + }, + { + "model": "cinema.ticket", + "pk": 9, + "fields": { + "movie_session": 5, + "order": 2, + "row": 1, + "seat": 5 + } + }, + { + "model": "cinema.ticket", + "pk": 10, + "fields": { + "movie_session": 6, + "order": 2, + "row": 1, + "seat": 6 + } + }, + { + "model": "cinema.ticket", + "pk": 11, + "fields": { + "movie_session": 7, + "order": 3, + "row": 4, + "seat": 7 + } + }, + { + "model": "cinema.ticket", + "pk": 12, + "fields": { + "movie_session": 8, + "order": 3, + "row": 3, + "seat": 7 + } + }, + { + "model": "cinema.ticket", + "pk": 13, + "fields": { + "movie_session": 8, + "order": 3, + "row": 5, + "seat": 4 + } + }, + { + "model": "cinema.ticket", + "pk": 14, + "fields": { + "movie_session": 8, + "order": 4, + "row": 4, + "seat": 4 + } + }, + { + "model": "cinema.ticket", + "pk": 15, + "fields": { + "movie_session": 1, + "order": 4, + "row": 2, + "seat": 3 + } + }, + { + "model": "cinema.ticket", + "pk": 16, + "fields": { + "movie_session": 2, + "order": 4, + "row": 5, + "seat": 3 + } + }, + { + "model": "user.user", + "pk": 1, + "fields": { + "password": "pbkdf2_sha256$320000$oZqdjfUqKC500V7kk3kMmb$TBVlOMhfJxWrxbUnNpWZK0+rYM242g7do/YM5tkhn+M=", + "last_login": null, + "is_superuser": true, + "username": "admin.user", + "first_name": "Admin", + "last_name": "User", + "email": "admin.user@cinema.com", + "is_staff": true, + "is_active": true, + "date_joined": "2022-08-09T09:06:18.876Z", + "groups": [], + "user_permissions": [] + } + }, + { + "model": "user.user", + "pk": 2, + "fields": { + "password": "pbkdf2_sha256$320000$73Z1Y57bcoscZ37s9rE9v0$4SEQ0TtXwJKzO5/CRdFSrTifatiPjkZ38gM2H8Kqsdg=", + "last_login": null, + "is_superuser": false, + "username": "ivan.khripko", + "first_name": "Ivan", + "last_name": "Khripko", + "email": "ivan.khripko@cinema.com", + "is_staff": false, + "is_active": true, + "date_joined": "2022-08-09T09:06:18.876Z", + "groups": [], + "user_permissions": [] + } + }, + { + "model": "user.user", + "pk": 3, + "fields": { + "password": "pbkdf2_sha256$320000$QtPol3T7x9quBj4BnbnVwW$UwT4kihkRfSvQEWEeuqVKwMgis2ikKVZfJDBcQMvOKY=", + "last_login": null, + "is_superuser": false, + "username": "mykola.hmara", + "first_name": "Mykola", + "last_name": "Hmara", + "email": "mykola.hmara@cinema.com", + "is_staff": false, + "is_active": true, + "date_joined": "2022-08-09T09:06:18.876Z", + "groups": [], + "user_permissions": [] + } + } +] diff --git a/manage.py b/manage.py index f64b2432..049c270e 100755 --- a/manage.py +++ b/manage.py @@ -1,22 +1,22 @@ -#!/usr/bin/env python -"""Django's command-line utility for administrative tasks.""" -import os -import sys - - -def main(): - """Run administrative tasks.""" - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cinema_service.settings") - try: - from django.core.management import execute_from_command_line - except ImportError as exc: - raise ImportError( - "Couldn't import Django. Are you sure it's installed and " - "available on your PYTHONPATH environment variable? Did you " - "forget to activate a virtual environment?" - ) from exc - execute_from_command_line(sys.argv) - - -if __name__ == "__main__": - main() +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cinema_service.settings") + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == "__main__": + main() diff --git a/requirements.txt b/requirements.txt index 108897e9..3f94b452 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ -Django==4.0.4 -djangorestframework==3.13.1 -flake8==5.0.4 -flake8-quotes==3.3.1 -flake8-variables-names==0.0.5 +Django==4.0.4 +djangorestframework==3.13.1 +flake8==5.0.4 +flake8-quotes==3.3.1 +flake8-variables-names==0.0.5 pep8-naming==0.13.2 \ No newline at end of file diff --git a/user/admin.py b/user/admin.py index f91be8f2..13b1b9a5 100644 --- a/user/admin.py +++ b/user/admin.py @@ -1,5 +1,5 @@ -from django.contrib import admin -from django.contrib.auth.admin import UserAdmin -from .models import User - -admin.site.register(User, UserAdmin) +from django.contrib import admin +from django.contrib.auth.admin import UserAdmin +from .models import User + +admin.site.register(User, UserAdmin) diff --git a/user/apps.py b/user/apps.py index 578292c2..802a97f0 100644 --- a/user/apps.py +++ b/user/apps.py @@ -1,6 +1,6 @@ -from django.apps import AppConfig - - -class UserConfig(AppConfig): - default_auto_field = "django.db.models.BigAutoField" - name = "user" +from django.apps import AppConfig + + +class UserConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "user" diff --git a/user/migrations/0001_initial.py b/user/migrations/0001_initial.py index 9de3c644..ff93ea63 100644 --- a/user/migrations/0001_initial.py +++ b/user/migrations/0001_initial.py @@ -1,132 +1,132 @@ -# Generated by Django 4.0.4 on 2022-05-10 11:54 - -import django.contrib.auth.models -import django.contrib.auth.validators -from django.db import migrations, models -import django.utils.timezone - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ("auth", "0012_alter_user_first_name_max_length"), - ] - - operations = [ - migrations.CreateModel( - name="User", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("password", models.CharField(max_length=128, verbose_name="password")), - ( - "last_login", - models.DateTimeField( - blank=True, null=True, verbose_name="last login" - ), - ), - ( - "is_superuser", - models.BooleanField( - default=False, - help_text="Designates that this user has all permissions without explicitly assigning them.", - verbose_name="superuser status", - ), - ), - ( - "username", - models.CharField( - error_messages={ - "unique": "A user with that username already exists." - }, - help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.", - max_length=150, - unique=True, - validators=[ - django.contrib.auth.validators.UnicodeUsernameValidator() - ], - verbose_name="username", - ), - ), - ( - "first_name", - models.CharField( - blank=True, max_length=150, verbose_name="first name" - ), - ), - ( - "last_name", - models.CharField( - blank=True, max_length=150, verbose_name="last name" - ), - ), - ( - "email", - models.EmailField( - blank=True, max_length=254, verbose_name="email address" - ), - ), - ( - "is_staff", - models.BooleanField( - default=False, - help_text="Designates whether the user can log into this admin site.", - verbose_name="staff status", - ), - ), - ( - "is_active", - models.BooleanField( - default=True, - help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.", - verbose_name="active", - ), - ), - ( - "date_joined", - models.DateTimeField( - default=django.utils.timezone.now, verbose_name="date joined" - ), - ), - ( - "groups", - models.ManyToManyField( - blank=True, - help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.", - related_name="user_set", - related_query_name="user", - to="auth.group", - verbose_name="groups", - ), - ), - ( - "user_permissions", - models.ManyToManyField( - blank=True, - help_text="Specific permissions for this user.", - related_name="user_set", - related_query_name="user", - to="auth.permission", - verbose_name="user permissions", - ), - ), - ], - options={ - "verbose_name": "user", - "verbose_name_plural": "users", - "abstract": False, - }, - managers=[ - ("objects", django.contrib.auth.models.UserManager()), - ], - ), - ] +# Generated by Django 4.0.4 on 2022-05-10 11:54 + +import django.contrib.auth.models +import django.contrib.auth.validators +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ("auth", "0012_alter_user_first_name_max_length"), + ] + + operations = [ + migrations.CreateModel( + name="User", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("password", models.CharField(max_length=128, verbose_name="password")), + ( + "last_login", + models.DateTimeField( + blank=True, null=True, verbose_name="last login" + ), + ), + ( + "is_superuser", + models.BooleanField( + default=False, + help_text="Designates that this user has all permissions without explicitly assigning them.", + verbose_name="superuser status", + ), + ), + ( + "username", + models.CharField( + error_messages={ + "unique": "A user with that username already exists." + }, + help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.", + max_length=150, + unique=True, + validators=[ + django.contrib.auth.validators.UnicodeUsernameValidator() + ], + verbose_name="username", + ), + ), + ( + "first_name", + models.CharField( + blank=True, max_length=150, verbose_name="first name" + ), + ), + ( + "last_name", + models.CharField( + blank=True, max_length=150, verbose_name="last name" + ), + ), + ( + "email", + models.EmailField( + blank=True, max_length=254, verbose_name="email address" + ), + ), + ( + "is_staff", + models.BooleanField( + default=False, + help_text="Designates whether the user can log into this admin site.", + verbose_name="staff status", + ), + ), + ( + "is_active", + models.BooleanField( + default=True, + help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.", + verbose_name="active", + ), + ), + ( + "date_joined", + models.DateTimeField( + default=django.utils.timezone.now, verbose_name="date joined" + ), + ), + ( + "groups", + models.ManyToManyField( + blank=True, + help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.", + related_name="user_set", + related_query_name="user", + to="auth.group", + verbose_name="groups", + ), + ), + ( + "user_permissions", + models.ManyToManyField( + blank=True, + help_text="Specific permissions for this user.", + related_name="user_set", + related_query_name="user", + to="auth.permission", + verbose_name="user permissions", + ), + ), + ], + options={ + "verbose_name": "user", + "verbose_name_plural": "users", + "abstract": False, + }, + managers=[ + ("objects", django.contrib.auth.models.UserManager()), + ], + ), + ] diff --git a/user/models.py b/user/models.py index 3d305253..48b7810b 100644 --- a/user/models.py +++ b/user/models.py @@ -1,5 +1,5 @@ -from django.contrib.auth.models import AbstractUser - - -class User(AbstractUser): - pass +from django.contrib.auth.models import AbstractUser + + +class User(AbstractUser): + pass diff --git a/user/tests.py b/user/tests.py index 7ce503c2..de8bdc00 100644 --- a/user/tests.py +++ b/user/tests.py @@ -1,3 +1,3 @@ -from django.test import TestCase - -# Create your tests here. +from django.test import TestCase + +# Create your tests here.