From 5722f0b7eac3ea0cab8ff437e800682fb9175ae9 Mon Sep 17 00:00:00 2001 From: maciejrusek Date: Wed, 18 Mar 2026 19:14:26 +0100 Subject: [PATCH] Added some logic --- README.md | 3 +- backend/apps/authors/models.py | 10 ++-- backend/apps/authors/serializers.py | 16 +++++ backend/apps/authors/urls.py | 8 +-- backend/apps/authors/views.py | 30 +++++----- backend/apps/books/models.py | 6 +- backend/apps/books/serializers.py | 53 +++++++++++++---- backend/apps/books/views.py | 2 +- backend/apps/shelf_items/apps.py | 2 +- backend/apps/shelf_items/models.py | 18 +++++- backend/apps/shelf_items/serializers.py | 77 +++++++++++++++++++++++++ backend/apps/shelf_items/urls.py | 9 +++ backend/apps/shelf_items/views.py | 21 ++++++- 13 files changed, 211 insertions(+), 44 deletions(-) create mode 100644 backend/apps/shelf_items/serializers.py create mode 100644 backend/apps/shelf_items/urls.py diff --git a/README.md b/README.md index e94762b..964f005 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ -shelf items -shelves/id/books \ No newline at end of file +shelves/id/items !!!! \ No newline at end of file diff --git a/backend/apps/authors/models.py b/backend/apps/authors/models.py index d0f263f..9c327c5 100644 --- a/backend/apps/authors/models.py +++ b/backend/apps/authors/models.py @@ -1,6 +1,6 @@ -# from django.db import models -# from apps.user.models import User +from django.db import models +from apps.user.models import User -# class Author(models.Model): -# user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="Authors") -# name = models.CharField(max_length=255) \ No newline at end of file +class Author(models.Model): + user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="authors") + name = models.CharField(max_length=255) \ No newline at end of file diff --git a/backend/apps/authors/serializers.py b/backend/apps/authors/serializers.py index e69de29..a938dda 100644 --- a/backend/apps/authors/serializers.py +++ b/backend/apps/authors/serializers.py @@ -0,0 +1,16 @@ +from rest_framework import serializers + +from apps.authors.models import Author + +class AuthorSerializer(serializers.ModelSerializer): + class Meta: + model = Author + fields = ["id", "name"] + read_only_fields = ["id"] + + def create(self, validated_data): + request = self.context["request"] + validated_data["user"] = request.user + + return super().create(validated_data) + \ No newline at end of file diff --git a/backend/apps/authors/urls.py b/backend/apps/authors/urls.py index 0203402..70042c4 100644 --- a/backend/apps/authors/urls.py +++ b/backend/apps/authors/urls.py @@ -1,9 +1,9 @@ from rest_framework.routers import DefaultRouter -# from apps.authors.views import AuthorsViewSet +from apps.authors.views import AuthorsViewSet urlpatterns = [] -# router = DefaultRouter() -# router.register("", viewset=AuthorsViewSet) -# urlpatterns += router.urls \ No newline at end of file +router = DefaultRouter() +router.register("", viewset=AuthorsViewSet) +urlpatterns += router.urls \ No newline at end of file diff --git a/backend/apps/authors/views.py b/backend/apps/authors/views.py index 7fff913..497d8be 100644 --- a/backend/apps/authors/views.py +++ b/backend/apps/authors/views.py @@ -1,20 +1,20 @@ -# from rest_framework import viewsets +from rest_framework import viewsets -# from apps.authors.models import Author -# from apps.authors.serializers import AuthorSerializer -# from rest_framework import viewsets -# from rest_framework.permissions import IsAuthenticated -# from rest_framework_simplejwt.authentication import JWTAuthentication +from apps.authors.models import Author +from apps.authors.serializers import AuthorSerializer +from rest_framework import viewsets +from rest_framework.permissions import IsAuthenticated +from rest_framework_simplejwt.authentication import JWTAuthentication -# class AuthorsViewSet(viewsets.ModelViewSet): -# queryset = Author.objects.select_related("shelf") -# serializer_class = AuthorSerializer +class AuthorsViewSet(viewsets.ModelViewSet): + queryset = Author.objects.all() + serializer_class = AuthorSerializer -# authentication_classes = [JWTAuthentication] -# permission_classes = [IsAuthenticated] + authentication_classes = [JWTAuthentication] + permission_classes = [IsAuthenticated] -# def get_queryset(self): -# return self.queryset.filter( -# shelf__user_id=self.request.user.pk -# ) + def get_queryset(self): + return self.queryset.filter( + user_id=self.request.user.pk + ) diff --git a/backend/apps/books/models.py b/backend/apps/books/models.py index 025efd0..24a4cfc 100644 --- a/backend/apps/books/models.py +++ b/backend/apps/books/models.py @@ -1,11 +1,11 @@ from django.db import models from apps.shelves.models import Shelf -# from apps.authors.models import Author +from apps.authors.models import Author from apps.user.models import User class Book(models.Model): - user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="Authors") - # authors = models.ManyToManyField(Author, related_name="books") + user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="books") + authors = models.ManyToManyField(Author, related_name="books") name = models.CharField(max_length=255) isbn = models.CharField(max_length=13) \ No newline at end of file diff --git a/backend/apps/books/serializers.py b/backend/apps/books/serializers.py index c83261b..d98f383 100644 --- a/backend/apps/books/serializers.py +++ b/backend/apps/books/serializers.py @@ -1,17 +1,27 @@ from rest_framework import serializers -from apps.books.models import Book from apps.shelves.serializers import ShelfSerializer +from apps.authors.serializers import AuthorSerializer +from apps.books.models import Book from apps.shelves.models import Shelf +from apps.authors.models import Author class BookSerializer(serializers.ModelSerializer): - #shelf = ShelfSerializer(read_only=True) - #shelf_id = serializers.PrimaryKeyRelatedField( - #queryset=Shelf.objects.all(), - #source="shelf", - #write_only=True - #) + shelf = ShelfSerializer(read_only=True) + shelf_id = serializers.PrimaryKeyRelatedField( + queryset=Shelf.objects.all(), + source="shelf", + write_only=True + ) + authors = AuthorSerializer(many=True, read_only=True) + authors_id = serializers.PrimaryKeyRelatedField( + queryset=Author.objects.all(), + source="authors", + many=True, + allow_null=True, + write_only=True + ) class Meta: model = Book @@ -19,7 +29,30 @@ class BookSerializer(serializers.ModelSerializer): "id", "name", "isbn", - #"shelf", - #"shelf_id" + "shelf", + "shelf_id", + "authors", + "authors_id" ] - read_only_fields = ["id"] \ No newline at end of file + read_only_fields = ["id"] + + + def __init__(self, instance=None, data=..., **kwargs): + super().__init__(instance, data, **kwargs) + + request = self.context.get("request") + if request and request.user: + self.fields["shelf_id"].queryset = Shelf.objects.filter( + user=request.user + ) + + self.fields["authors_id"].queryset = Author.objects.filter( + user=request.user + ) + + + def create(self, validated_data): + request = self.context["request"] + validated_data["user"] = request.user + + return super().create(validated_data) \ No newline at end of file diff --git a/backend/apps/books/views.py b/backend/apps/books/views.py index 08f78b6..67aa063 100644 --- a/backend/apps/books/views.py +++ b/backend/apps/books/views.py @@ -16,4 +16,4 @@ class BooksViewSet(viewsets.ModelViewSet): def get_queryset(self): return self.queryset.filter( shelf__user_id=self.request.user.pk - ) + ).prefetch_related("authors") diff --git a/backend/apps/shelf_items/apps.py b/backend/apps/shelf_items/apps.py index 95c030a..35e40bb 100644 --- a/backend/apps/shelf_items/apps.py +++ b/backend/apps/shelf_items/apps.py @@ -2,4 +2,4 @@ from django.apps import AppConfig class ShelfItemsConfig(AppConfig): - name = 'shelf_items' + name = 'apps.shelf_items' diff --git a/backend/apps/shelf_items/models.py b/backend/apps/shelf_items/models.py index 71a8362..2922bcc 100644 --- a/backend/apps/shelf_items/models.py +++ b/backend/apps/shelf_items/models.py @@ -1,3 +1,19 @@ +from django.db.models import Q, F from django.db import models -# Create your models here. +from apps.books.models import Book +from apps.shelves.models import Shelf + +class ShelfItem(models.Model): + book = models.ForeignKey(Book, on_delete=models.CASCADE, related_name="shelf_items") + shelf = models.ForeignKey(Shelf, on_delete=models.CASCADE, related_name="book_items") + + quantity = models.PositiveIntegerField(default=0) + + class Meta: + constraints = [ + models.UniqueConstraint( + fields=["book", "shelf"], + name="unique_book_per_shelf" + ), + ] \ No newline at end of file diff --git a/backend/apps/shelf_items/serializers.py b/backend/apps/shelf_items/serializers.py new file mode 100644 index 0000000..0440ad0 --- /dev/null +++ b/backend/apps/shelf_items/serializers.py @@ -0,0 +1,77 @@ +from rest_framework import serializers + +from apps.shelf_items.models import ShelfItem +from apps.books.models import Book +from apps.shelves.models import Shelf +from apps.shelves.serializers import ShelfSerializer +from apps.books.serializers import BookSerializer + +class ShelfItemSerializer(serializers.ModelSerializer): + shelf = ShelfSerializer(read_only=True) + shelf_id = serializers.PrimaryKeyRelatedField( + queryset=Shelf.objects.all(), + source="shelf", + write_only=True + ) + + book = BookSerializer(read_only=True) + book_id = serializers.PrimaryKeyRelatedField( + queryset=Book.objects.all(), + source="book", + write_only=True + ) + + class Meta: + model = ShelfItem + fields = [ + "id", + "shelf", + "shelf_id", + "book", + "book_id", + "quantity" + ] + read_only_fields = ["id"] + + def __init__(self, instance=None, data=..., **kwargs): + super().__init__(instance, data, **kwargs) + + request = self.context.get("request") + if request and request.user: + self.fields["shelf_id"].queryset = Shelf.objects.filter( + user=request.user + ) + + self.fields["book_id"].queryset = Book.objects.filter( + user=request.user + ) + + def validate(self, attrs): + attrs = super().validate(attrs) + + book = attrs.get("book") + shelf = attrs.get("shelf") + + if book and shelf: + qs = ShelfItem.objects.filter( + book=book, + shelf=shelf + ) + + if self.instance: + qs = qs.exclude(pk=self.instance.pk) + + if qs.exists(): + raise serializers.ValidationError( + "This Book already exists in shelf!" + ) + + if book.user_id != shelf.user_id: + raise serializers.ValidationError( + "Book and Shelf must be from the same user!" + ) + + return attrs + + + diff --git a/backend/apps/shelf_items/urls.py b/backend/apps/shelf_items/urls.py new file mode 100644 index 0000000..d2b1b22 --- /dev/null +++ b/backend/apps/shelf_items/urls.py @@ -0,0 +1,9 @@ +from rest_framework.routers import DefaultRouter + +from apps.shelf_items.views import ShelfItemsViewSet + +urlpatterns = [] + +router = DefaultRouter() +router.register("", viewset=ShelfItemsViewSet) +urlpatterns += router.urls \ No newline at end of file diff --git a/backend/apps/shelf_items/views.py b/backend/apps/shelf_items/views.py index 91ea44a..7e9bf26 100644 --- a/backend/apps/shelf_items/views.py +++ b/backend/apps/shelf_items/views.py @@ -1,3 +1,20 @@ -from django.shortcuts import render +from rest_framework import viewsets -# Create your views here. +from apps.shelf_items.models import ShelfItem +from apps.shelf_items.serializers import ShelfItemSerializer +from rest_framework import viewsets +from rest_framework.permissions import IsAuthenticated +from rest_framework_simplejwt.authentication import JWTAuthentication + + +class ShelfItemsViewSet(viewsets.ModelViewSet): + queryset = ShelfItem.objects.all() + serializer_class = ShelfItemSerializer + + authentication_classes = [JWTAuthentication] + permission_classes = [IsAuthenticated] + + def get_queryset(self): + return ShelfItem.objects.filter( + shelf__user_id=self.request.user.pk, + ).select_related("book", "shelf").prefetch_related("book__authors")