added new model favorites

This commit is contained in:
Anatoly 2019-09-06 17:55:17 +03:00
parent e1d6455e81
commit 1848bafd64
13 changed files with 190 additions and 2 deletions

View File

@ -4,6 +4,7 @@ from rest_framework import serializers
from comment import models as comment_models from comment import models as comment_models
from comment.serializers import common as comment_serializers from comment.serializers import common as comment_serializers
from establishment import models from establishment import models
from favorites.models import Favorites
from location.serializers import AddressSerializer from location.serializers import AddressSerializer
from main.serializers import MetaDataContentSerializer, AwardSerializer, CurrencySerializer from main.serializers import MetaDataContentSerializer, AwardSerializer, CurrencySerializer
from review import models as review_models from review import models as review_models
@ -175,6 +176,8 @@ class EstablishmentDetailSerializer(EstablishmentListSerializer):
best_price_menu = serializers.DecimalField(max_digits=14, decimal_places=2, read_only=True) best_price_menu = serializers.DecimalField(max_digits=14, decimal_places=2, read_only=True)
best_price_carte = serializers.DecimalField(max_digits=14, decimal_places=2, read_only=True) best_price_carte = serializers.DecimalField(max_digits=14, decimal_places=2, read_only=True)
in_favorites = serializers.SerializerMethodField()
class Meta: class Meta:
"""Meta class.""" """Meta class."""
@ -197,7 +200,7 @@ class EstablishmentDetailSerializer(EstablishmentListSerializer):
'employees', 'employees',
'menu', 'menu',
'best_price_menu', 'best_price_menu',
'best_price_carte' 'best_price_carte',
) )
def get_comments(self, obj): def get_comments(self, obj):
@ -261,3 +264,46 @@ class EstablishmentCommentRUDSerializer(comment_serializers.CommentSerializer):
'nickname', 'nickname',
'profile_pic', 'profile_pic',
] ]
class EstablishmentFavoritesCreateSerializer(serializers.ModelSerializer):
"""Create comment serializer"""
class Meta:
"""Serializer for model Comment"""
model = Favorites
fields = [
'id',
'created',
]
def get_user(self):
"""Get user from request"""
return self.context.get('request').user
def validate(self, attrs):
"""Override validate method"""
# Check establishment object
establishment_id = self.context.get('request').parser_context.get('kwargs').get('pk')
establishment_qs = models.Establishment.objects.filter(id=establishment_id)
# Check establishment obj by pk from lookup_kwarg
if not establishment_qs.exists():
return serializers.ValidationError()
# Check existence in favorites
if self.get_user().favorites.by_content_type(app_label='establishment',
model='establishment',
object_id=establishment_id).exists():
raise serializers.ValidationError()
attrs['establishment'] = establishment_qs.first()
return attrs
def create(self, validated_data, *args, **kwargs):
"""Override create method"""
validated_data.update({
'user': self.get_user(),
'content_object': validated_data.pop('establishment')
})
return super().create(validated_data)

View File

@ -13,4 +13,6 @@ urlpatterns = [
name='create-comment'), name='create-comment'),
path('<int:pk>/comment/<int:comment_id>/', views.EstablishmentCommentRUDView.as_view(), path('<int:pk>/comment/<int:comment_id>/', views.EstablishmentCommentRUDView.as_view(),
name='rud-comment'), name='rud-comment'),
path('<int:pk>/favorites/', views.EstablishmentFavoritesCreateView.as_view()),
path('<int:pk>/favorites/<int:favorites_id>/', views.EstablishmentFavoritesDestroyView.as_view()),
] ]

View File

@ -6,6 +6,7 @@ from rest_framework import generics, permissions
from comment import models as comment_models from comment import models as comment_models
from establishment import filters from establishment import filters
from establishment import models, serializers from establishment import models, serializers
from favorites import models as favorites_models
from utils.views import JWTGenericViewMixin from utils.views import JWTGenericViewMixin
@ -46,7 +47,7 @@ class EstablishmentTypeListView(JWTGenericViewMixin, generics.ListAPIView):
class EstablishmentCommentCreateView(generics.CreateAPIView): class EstablishmentCommentCreateView(generics.CreateAPIView):
"""View for create new comment.""" """View for create new comment."""
serializer_class = serializers.EstablishmentCommentCreateSerializer serializer_class = serializers.EstablishmentCommentCreateSerializer
queryset = comment_models.Comment.objects.order_by('-created') queryset = comment_models.Comment.objects.all()
class EstablishmentCommentRUDView(generics.RetrieveUpdateDestroyAPIView): class EstablishmentCommentRUDView(generics.RetrieveUpdateDestroyAPIView):
@ -77,3 +78,34 @@ class EstablishmentCommentRUDView(generics.RetrieveUpdateDestroyAPIView):
self.check_object_permissions(self.request, comment_obj) self.check_object_permissions(self.request, comment_obj)
return comment_obj return comment_obj
class EstablishmentFavoritesCreateView(generics.CreateAPIView):
"""View for adding establishment to favorites."""
serializer_class = serializers.EstablishmentFavoritesCreateSerializer
queryset = favorites_models.Favorites.objects.all()
class EstablishmentFavoritesDestroyView(generics.DestroyAPIView):
"""View for destroy establishment from favorites."""
def get_object(self):
"""
Returns the object the view is displaying.
"""
lookup_url_kwargs = ('pk', 'favorites_id')
assert lookup_url_kwargs not in self.kwargs.keys(), (
'Expected view %s to be called with a URL keyword argument '
'named "%s". Fix your URL conf, or set the `.lookup_field` '
'attribute on the view correctly.' %
(self.__class__.__name__, lookup_url_kwargs)
)
obj = get_object_or_404(
self.request.user.favorites.by_content_type(app_label='establishment',
model='establishment',
object_id=self.kwargs['pk'])
.filter(id=self.kwargs['favorites_id']))
# May raise a permission denied
self.check_object_permissions(self.request, obj)
return obj

View File

11
apps/favorites/admin.py Normal file
View File

@ -0,0 +1,11 @@
from django.contrib import admin
from favorites import models
@admin.register(models.Favorites)
class FavoritesModelAdmin(admin.ModelAdmin):
"""Admin model for model Favorites"""
list_display = ('id', 'user', )
list_filter = ('user', )

7
apps/favorites/apps.py Normal file
View File

@ -0,0 +1,7 @@
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class FavoritesConfig(AppConfig):
name = 'favorites'
verbose_name = _('Favorites')

View File

@ -0,0 +1,34 @@
# Generated by Django 2.2.4 on 2019-09-06 12:36
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
initial = True
dependencies = [
('contenttypes', '0002_remove_content_type_name'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Favorites',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', models.DateTimeField(default=django.utils.timezone.now, editable=False, verbose_name='Date created')),
('modified', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('object_id', models.PositiveIntegerField()),
('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='favorites', to=settings.AUTH_USER_MODEL, verbose_name='User')),
],
options={
'verbose_name': 'Favorites',
'verbose_name_plural': 'Favorites',
},
),
]

View File

44
apps/favorites/models.py Normal file
View File

@ -0,0 +1,44 @@
from django.contrib.contenttypes import fields as generic
from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.utils.translation import gettext_lazy as _
from utils.methods import get_contenttype
from utils.models import ProjectBaseMixin
class FavoritesQuerySet(models.QuerySet):
"""QuerySet for model Favorites"""
def by_content_type(self, app_label, model, object_id):
"""Filter QuerySet by ContentType."""
return self.filter(content_type=get_contenttype(app_label=app_label,
model=model),
object_id=object_id)
def by_user(self, user):
"""Filter by user"""
return self.filter(user=user)
class Favorites(ProjectBaseMixin):
"""Favorites model."""
user = models.ForeignKey('account.User',
on_delete=models.CASCADE,
related_name='favorites',
verbose_name=_('User'))
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
objects = FavoritesQuerySet.as_manager()
class Meta:
"""Meta class."""
verbose_name = _('Favorites')
verbose_name_plural = _('Favorites')
def __str__(self):
"""String representation."""
return f'{self.id}'

View File

@ -0,0 +1 @@
"""Serializers for app favorites."""

1
apps/favorites/tests.py Normal file
View File

@ -0,0 +1 @@
# Create your tests here.

View File

@ -4,6 +4,7 @@ import re
import string import string
from django.conf import settings from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.http.request import HttpRequest from django.http.request import HttpRequest
from django.utils.timezone import datetime from django.utils.timezone import datetime
from rest_framework.request import Request from rest_framework.request import Request
@ -78,3 +79,11 @@ def generate_string_code(size=64,
chars=string.ascii_lowercase + string.ascii_uppercase + string.digits): chars=string.ascii_lowercase + string.ascii_uppercase + string.digits):
"""Generate string code.""" """Generate string code."""
return ''.join([random.SystemRandom().choice(chars) for _ in range(size)]) return ''.join([random.SystemRandom().choice(chars) for _ in range(size)])
def get_contenttype(app_label: str, model: str):
"""Get ContentType instance by app_label and model"""
if app_label and model:
qs = ContentType.objects.filter(app_label=app_label, model=model)
if qs.exists():
return qs.first()

View File

@ -68,6 +68,7 @@ PROJECT_APPS = [
'timetable.apps.TimetableConfig', 'timetable.apps.TimetableConfig',
'review.apps.ReviewConfig', 'review.apps.ReviewConfig',
'comment.apps.CommentConfig', 'comment.apps.CommentConfig',
'favorites.apps.FavoritesConfig',
] ]
EXTERNAL_APPS = [ EXTERNAL_APPS = [