Merge branch 'feature/news-rating' into 'develop'

Feature/news rating

See merge request gm/gm-backend!46
This commit is contained in:
d.kuzmenko 2019-10-04 08:33:13 +00:00
commit f9247477f9
12 changed files with 104 additions and 2 deletions

View File

@ -5,6 +5,8 @@ from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from rest_framework.reverse import reverse
from utils.models import BaseAttributes, TJSONField, TranslatedFieldsMixin
from django.contrib.contenttypes.models import ContentType
from rating.models import Rating
from random import sample as random_sample
@ -27,6 +29,9 @@ class NewsType(models.Model):
class NewsQuerySet(models.QuerySet):
"""QuerySet for model News"""
def rating_value(self):
return self.annotate(rating=models.Count('ratings__ip', distinct=True))
def with_base_related(self):
"""Return qs with related objects."""
return self.select_related('news_type', 'country').prefetch_related('tags')
@ -132,6 +137,8 @@ class News(BaseAttributes, TranslatedFieldsMixin):
verbose_name=_('country'))
tags = generic.GenericRelation(to='main.MetaDataContent')
ratings = generic.GenericRelation(Rating)
objects = NewsQuerySet.as_manager()
class Meta:

View File

@ -1,7 +1,7 @@
"""News app views."""
from rest_framework import generics, permissions
from news import filters, models, serializers
from rating.tasks import add_rating
class NewsMixinView:
"""News mixin."""
@ -34,7 +34,6 @@ class NewsDetailView(NewsMixinView, generics.RetrieveAPIView):
"""Override get_queryset method."""
return super().get_queryset().with_extended_related()
class NewsTypeListView(generics.ListAPIView):
"""NewsType list view."""
@ -76,3 +75,7 @@ class NewsBackOfficeRUDView(NewsBackOfficeMixinView,
serializer_class = serializers.NewsBackOfficeDetailSerializer
def get(self, request, pk, *args, **kwargs):
add_rating(remote_addr=request.META.get('REMOTE_ADDR'),
pk=pk, model='news', app_label='news')
return self.retrieve(request, *args, **kwargs)

0
apps/rating/__init__.py Normal file
View File

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

@ -0,0 +1,11 @@
from django.contrib import admin
from rating import models
from rating import tasks
@admin.register(models.Rating)
class RatingAdmin(admin.ModelAdmin):
"""Rating type admin conf."""
list_display = ['name', 'ip']
list_display_links = ['name']

5
apps/rating/apps.py Normal file
View File

@ -0,0 +1,5 @@
from django.apps import AppConfig
class RatingConfig(AppConfig):
name = 'rating'

View File

@ -0,0 +1,28 @@
# Generated by Django 2.2.4 on 2019-10-02 11:32
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('contenttypes', '0002_remove_content_type_name'),
]
operations = [
migrations.CreateModel(
name='Rating',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('object_id', models.PositiveIntegerField()),
('ip', models.GenericIPAddressField(verbose_name='ip')),
('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType')),
],
options={
'verbose_name': 'rating',
},
),
]

View File

19
apps/rating/models.py Normal file
View File

@ -0,0 +1,19 @@
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.utils.translation import gettext_lazy as _
class Rating(models.Model):
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
ip = models.GenericIPAddressField(verbose_name=_('ip'))
@property
def name(self):
# Check if Generic obj has name or title
if hasattr(self.content_object, 'name'):
return self.content_object.name
if hasattr(self.content_object, 'title'):
return self.content_object.title_translated

22
apps/rating/tasks.py Normal file
View File

@ -0,0 +1,22 @@
from datetime import timedelta
from celery import task
from rating.models import Rating
from django.contrib.contenttypes.models import ContentType
def add_rating(remote_addr, pk, model, app_label):
add.apply_async(
(remote_addr, pk, model, app_label), countdown=60 * 60
)
@task
def add(remote_addr, pk, model, app_label):
rating = Rating()
rating.ip = remote_addr
rating.object_id = pk
rating.content_type = ContentType.objects.get(app_label=app_label, model=model)
rating.save()

3
apps/rating/tests.py Normal file
View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

3
apps/rating/views.py Normal file
View File

@ -0,0 +1,3 @@
from django.shortcuts import render
# Create your views here.

View File

@ -71,6 +71,7 @@ PROJECT_APPS = [
'review.apps.ReviewConfig',
'comment.apps.CommentConfig',
'favorites.apps.FavoritesConfig',
'rating.apps.RatingConfig',
]
EXTERNAL_APPS = [