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()