Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/reviews #5

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions api_yamdb/api/admin.py

This file was deleted.

8 changes: 8 additions & 0 deletions api_yamdb/api/permissions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from rest_framework import permissions


class IsOwnerOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
return request.method in permissions.SAFE_METHODS or (
obj.author == request.user
)
43 changes: 43 additions & 0 deletions api_yamdb/api/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from rest_framework import serializers
from rest_framework.validators import UniqueValidator
from reviews.models import Comment, Review


class CommentSerializer(serializers.ModelSerializer):
author = serializers.SlugRelatedField(
read_only=True,
slug_field='username'
)

class Meta:
model = Comment
fields = '__all__'
read_only_fields = ('reviews', )


class ReviewSerializer(serializers.ModelSerializer):
author = serializers.PrimaryKeyRelatedField(
source='author.username', read_only=True
)
comments = CommentSerializer(many=True, read_only=True)
text = serializers.CharField(allow_null=True)
id = serializers.ReadOnlyField()
author_username = serializers.ReadOnlyField(source='author.username')

class Meta:
model = Review
fields = '__all__'
validators = [
UniqueValidator(
queryset=Review.objects.all(),
message='Вы уже написали отзыв к данному произведению'
)
]

def get_rating(self, obj):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Про рейтинг ты интересовался..

Получается по факту, что пользователь приходит и просто здесь проставляет оценку, которая в review имеет поле/field 'score', ее не нужно усреднять, он ставит 1 оценку. (т.к. эта часть приходится на мою в Titles. Там считается rating avg по оценкам пользователей:
<rating = serializers.IntegerField(
source='reviews__score__avg', read_only=True)>

То что у тебя округление до 2го знака после точки (что так можно я совсем недавно узнал)

reviews = Review.objects.filter(title=obj.title)
if reviews:
total_score = sum([review.score for review in reviews])
rating = total_score / len(reviews)
return round(rating, 2)
return None
3 changes: 0 additions & 3 deletions api_yamdb/api/tests.py

This file was deleted.

15 changes: 7 additions & 8 deletions api_yamdb/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
# from .views import CategoryViewSet
# from .views import GenreViewSet
# from .views import TitleViewSet
# from .views import ReviewViewSet
# from .views import CommentViewSet
from .views import ReviewViewSet, CommentViewSet
# from .views import register
# from .views import get_jwt_token

Expand All @@ -16,14 +15,14 @@
# router.register(r'categories', CategoryViewSet, basename='categories')
# router.register(r'genres', GenreViewSet, basename='genres')
# router.register(r'titles', TitleViewSet, basename='titles')
# router.register(r'titles/(?P<title_id>\d+)/reviews', ReviewViewSet, basename='reviews')
# router.register(r'titles/(?P<title_id>\d+)/reviews/(?P<review_id>\d+)/comments', CommentViewSet, basename='comments')
router.register(r'titles/(?P<title_id>\d+)/reviews', ReviewViewSet, basename='reviews')
router.register(r'titles/(?P<title_id>\d+)/reviews/(?P<review_id>\d+)/comments', CommentViewSet, basename='comments')


urlpatterns = [
# path('v1/', include('djoser.urls')),
# path('v1/', include('djoser.urls.jwt')),
path('v1/', include('djoser.urls')),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

из-за 23, 24 не нужны

path('v1/', include('djoser.urls.jwt')),
path('v1/', include(router.urls)),
# path('v1/auth/signup/', register, name='register'),
# path('v1/auth/token/', get_jwt_token, name='token')
# path('v1/auth/signup/', register, name='register'),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

26, 27 будем использовать

# path('v1/auth/token/', get_jwt_token, name='token')
]
39 changes: 37 additions & 2 deletions api_yamdb/api/views.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,38 @@
from django.shortcuts import render
from django.shortcuts import get_object_or_404
from django.db.models import Avg
from reviews.models import Review, Title
from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticatedOrReadOnly
from rest_framework_simplejwt.authentication import JWTAuthentication

# Create your views here.
from .permissions import IsOwnerOrReadOnly
from .serializers import ReviewSerializer, CommentSerializer


class ReviewViewSet(viewsets.ModelViewSet):
queryset = Review.objects.all()
serializer_class = ReviewSerializer
permission_classes = (IsOwnerOrReadOnly, IsAuthenticatedOrReadOnly,)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Вместо таких классов разрешений возможно IsAdminModeratorOrReadonly больше подходит

authentication_classes = [JWTAuthentication]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

не совсем понимаю что это дает


def perform_create(self, serializer):
serializer.save(author=self.request.user)
title_id = self.request.data.get('title')
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

в ветке которую предложил я это по другому сделано(плиз посмотри)

reviews = Review.objects.filter(title_id=title_id)
rating = reviews.aggregate(Avg('score'))['score__avg']
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rating здесь не нужно высчитывать, только score вносить нужно 1 - 10. Считаем в ReadOnlyTitleSerializer (в моем куске кода)

Title.objects.filter(id=title_id).update(rating=rating)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

это сделано у меня в ReadOnlyTitleSerializer,



class CommentViewSet(viewsets.ModelViewSet):
serializer_class = CommentSerializer
permission_classes = (IsOwnerOrReadOnly, IsAuthenticatedOrReadOnly,)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IsAdminModeratorOwnerOrReadOnly

authentication_classes = [JWTAuthentication]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

думаю это не нужно


def get_queryset(self):
review = get_object_or_404(Review, pk=self.kwargs.get('review_id'))
return review.comments

def perform_create(self, serializer):
review_id = self.kwargs.get('rewiew_id')
review = get_object_or_404(Review, pk=review_id)
serializer.save(author=self.request.user, review=review)
2 changes: 2 additions & 0 deletions api_yamdb/api_yamdb/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 3,
}

SIMPLE_JWT = {
Expand Down
18 changes: 9 additions & 9 deletions api_yamdb/reviews/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class Category(models.Model):

def __str__(self):
return self.name

class Meta:
ordering = ['name']

Expand Down Expand Up @@ -42,7 +42,7 @@ class Title(models.Model):

def __str__(self):
return self.name

class Meta:
ordering = ['name']

Expand All @@ -52,7 +52,7 @@ class GenreTitle(models.Model):
Title, on_delete=models.CASCADE)
genre = models.ForeignKey(
Genre, on_delete=models.CASCADE)

def __str__(self):
return f'{self.title}, genre: {self.genre}'

Expand All @@ -63,14 +63,14 @@ class Review(models.Model):
related_name='reviews')
text = models.TextField()
author = models.ForeignKey(
User, on_delete=models.CASCADE,
User, on_delete=models.CASCADE,
related_name='reviews')
score = models.IntegerField(
validators=[
MinValueValidator(1),
MaxValueValidator(10)
]
)
)
pub_date = models.DateTimeField(
'Publication date', auto_now=True)

Expand All @@ -79,19 +79,19 @@ class Meta:
ordering = ['pub_date']
constraints = [
models.UniqueConstraint(
fields=('title', 'author',),
name='unique_review'
fields=('title', 'author',),
name='unique_review'
)
]


class Comment(models.Model):
review = models.ForeignKey(
Review, on_delete=models.CASCADE,
Review, on_delete=models.CASCADE,
related_name='comments')
text = models.TextField()
author = models.ForeignKey(
User, on_delete=models.CASCADE,
User, on_delete=models.CASCADE,
related_name='comments')
pub_date = models.DateTimeField('Publication date', auto_now_add=True)

Expand Down
3 changes: 0 additions & 3 deletions api_yamdb/reviews/tests.py

This file was deleted.

7 changes: 3 additions & 4 deletions api_yamdb/users/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from django.contrib.auth.models import AbstractUser
from reviews.validators import validate_username

# Create your models here.

class User(AbstractUser):
ADMIN = 'admin'
Expand Down Expand Up @@ -32,12 +31,12 @@ class User(AbstractUser):

@property
def is_moderator(self):
return self.role == self.MODERATOR
return self.role == self.MODERATOR

@property
def is_admin(self):
return self.role == self.ADMIN

USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']

Expand All @@ -49,4 +48,4 @@ class Meta:
check=~models.Q(username__iexact="me"),
name="username_is_not_me"
)
]
]