diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/book-list-api.iml b/.idea/book-list-api.iml new file mode 100644 index 0000000..13c7c03 --- /dev/null +++ b/.idea/book-list-api.iml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..ac21435 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..d8cc06e --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,18 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..9f4b0e6 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..ce73e4d --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/api/__pycache__/__init__.cpython-313.pyc b/api/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000..a8afd64 Binary files /dev/null and b/api/__pycache__/__init__.cpython-313.pyc differ diff --git a/api/__pycache__/settings.cpython-313.pyc b/api/__pycache__/settings.cpython-313.pyc new file mode 100644 index 0000000..3ed8507 Binary files /dev/null and b/api/__pycache__/settings.cpython-313.pyc differ diff --git a/api/__pycache__/urls.cpython-313.pyc b/api/__pycache__/urls.cpython-313.pyc new file mode 100644 index 0000000..78a7c05 Binary files /dev/null and b/api/__pycache__/urls.cpython-313.pyc differ diff --git a/api/__pycache__/wsgi.cpython-313.pyc b/api/__pycache__/wsgi.cpython-313.pyc new file mode 100644 index 0000000..0bc4a85 Binary files /dev/null and b/api/__pycache__/wsgi.cpython-313.pyc differ diff --git a/books/__pycache__/__init__.cpython-313.pyc b/books/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000..6d47ce3 Binary files /dev/null and b/books/__pycache__/__init__.cpython-313.pyc differ diff --git a/books/__pycache__/admin.cpython-313.pyc b/books/__pycache__/admin.cpython-313.pyc new file mode 100644 index 0000000..a1ace53 Binary files /dev/null and b/books/__pycache__/admin.cpython-313.pyc differ diff --git a/books/__pycache__/apps.cpython-313.pyc b/books/__pycache__/apps.cpython-313.pyc new file mode 100644 index 0000000..34961d4 Binary files /dev/null and b/books/__pycache__/apps.cpython-313.pyc differ diff --git a/books/__pycache__/models.cpython-313.pyc b/books/__pycache__/models.cpython-313.pyc new file mode 100644 index 0000000..d4c8b75 Binary files /dev/null and b/books/__pycache__/models.cpython-313.pyc differ diff --git a/books/__pycache__/serializers.cpython-313.pyc b/books/__pycache__/serializers.cpython-313.pyc new file mode 100644 index 0000000..aa402c8 Binary files /dev/null and b/books/__pycache__/serializers.cpython-313.pyc differ diff --git a/books/__pycache__/urls.cpython-313.pyc b/books/__pycache__/urls.cpython-313.pyc new file mode 100644 index 0000000..35e21be Binary files /dev/null and b/books/__pycache__/urls.cpython-313.pyc differ diff --git a/books/__pycache__/views.cpython-313.pyc b/books/__pycache__/views.cpython-313.pyc new file mode 100644 index 0000000..f3d122a Binary files /dev/null and b/books/__pycache__/views.cpython-313.pyc differ diff --git a/books/migrations/0001_initial.py b/books/migrations/0001_initial.py new file mode 100644 index 0000000..794ae4c --- /dev/null +++ b/books/migrations/0001_initial.py @@ -0,0 +1,63 @@ +# Generated by Django 5.2.9 on 2025-12-06 20:49 + +import books.models +import django.contrib.auth.models +import django.contrib.auth.validators +import django.core.validators +import django.db.models.deletion +import django.utils.timezone +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('auth', '0012_alter_user_first_name_max_length'), + ] + + operations = [ + migrations.CreateModel( + name='CustomUser', + 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')), + ('avatar', models.ImageField(upload_to=books.models.upload_avatar)), + ('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()), + ], + ), + migrations.CreateModel( + name='Book', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('note', models.PositiveSmallIntegerField(blank=True, default=0, null=True, validators=[django.core.validators.MaxValueValidator(10)], verbose_name='note')), + ('title', models.CharField(max_length=255)), + ('author', models.CharField(max_length=255)), + ('illustration', models.ImageField(upload_to=books.models.upload_illustration)), + ('state', models.CharField(choices=[('PLAN', 'Plan to Read'), ('READING', 'Reading'), ('COMPLETED', 'Completed'), ('DROPPED', 'Dropped')], db_index=True, default='PLAN', max_length=10, verbose_name='state')), + ('added_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='books', to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/books/migrations/__init__.py b/books/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/books/migrations/__pycache__/0001_initial.cpython-313.pyc b/books/migrations/__pycache__/0001_initial.cpython-313.pyc new file mode 100644 index 0000000..9b49166 Binary files /dev/null and b/books/migrations/__pycache__/0001_initial.cpython-313.pyc differ diff --git a/books/migrations/__pycache__/__init__.cpython-313.pyc b/books/migrations/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000..c14e25a Binary files /dev/null and b/books/migrations/__pycache__/__init__.cpython-313.pyc differ diff --git a/books/views.py b/books/views.py index 698b0f8..5b68e80 100644 --- a/books/views.py +++ b/books/views.py @@ -1,4 +1,5 @@ from rest_framework.decorators import api_view +from rest_framework.parsers import FormParser, MultiPartParser from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.permissions import IsAuthenticatedOrReadOnly, IsAuthenticated @@ -9,6 +10,7 @@ from .serializers import BookSerializer class BookListCreateView(APIView): permission_classes = [IsAuthenticatedOrReadOnly] + parser_classes = [MultiPartParser, FormParser] def get(self, request): books = Book.objects.all()