I have two models: Book and Reply

*the model Book*


class Book(models.Model):
    """
    Model for books
    """

    # other fields

    replies = GenericRelation(Reply, related_query_name='books')

    # managers
    objects = models.Manager()
    objects = BookManager.from_queryset(BookQuerySet)()

    # other methods

    def get_rating(self):
        """Getting rating of book on based scopes."""

        # return 
self.__class__.objects.books_with_rating().get(pk=self.pk).rating
        replies_with_total_scope = self.replies.replies_with_total_scope()
        rating = replies_with_total_scope.aggregate(rating=models.Avg(
'total_scope'))['rating']
        rating = rating or 0
        return round(rating, 4)
    get_rating.admin_order_field = 'rating'
    get_rating.short_description = _('Rating')


*model Reply*

from django.utils import timezone
# from django.core.exceptions import ValidationError
from django.contrib.postgres.fields import ArrayField
from django.core.validators import MinLengthValidator, MaxValueValidator
from django.utils.translation import ugettext_lazy as _
from django.db import models
from django.conf import settings

from mylabour.models import BaseGenericModel
from mylabour.validators import MaxCountWordsValidator, 
MinCountWordsValidator, OnlyLettersValidator

from .querysets import ReplyQuerySet

class Reply(BaseGenericModel):
    """
    Model for reply about other objects.
    """

    MAX_SCOPE = 5
    MIN_SCOPE = 1

    account = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='replies',
        verbose_name=_('user'),
    )
    impress = models.CharField(
        _('impress (brief)'),
        max_length=50,
        validators=[MinLengthValidator(10)],
        help_text=_('From 10 to 50 characters.'),
    )
    advantages = ArrayField(
        models.CharField(max_length=20, validators=[OnlyLettersValidator]),
        size=10,
        verbose_name=_('advantages'),
        help_text=_('Listing from 1 to 10 words separated commas.'),
        error_messages={
            'blank': 'Enter at least one word.',
            # 'item_invalid': 'Word is not correct.',
        }
    )
    disadvantages = ArrayField(
        models.CharField(max_length=20, validators=[OnlyLettersValidator]),
        help_text=_('Listing from 1 to 10 words separated commas.'),
        verbose_name=_('disadvantages'),
        size=10,
        error_messages={
            'blank': 'Enter at least one word.',
            'item_invalid': 'Word is not correct.',
        }
    )
    text_reply = models.TextField(
        _('text of reply'),
        validators=[MinCountWordsValidator(10), MaxCountWordsValidator(100
)],
        help_text=_('From 10 to 100 words.'),
    )
    scope_for_content = models.PositiveSmallIntegerField(
        _('scope for content'),
        default=MIN_SCOPE,
        validators=[
            MaxValueValidator(MAX_SCOPE, _('The scope for content must be 
from 1 to %d' % MAX_SCOPE))
        ])
    scope_for_style = models.PositiveSmallIntegerField(
        _('scope for style'),
        default=MIN_SCOPE,
        validators=[
            MaxValueValidator(MAX_SCOPE, _('The scope for style must be 
from 1 to %d' % MAX_SCOPE))
        ])
    scope_for_language = models.PositiveSmallIntegerField(
        _('scope for language'),
        default=MIN_SCOPE,
        validators=[
            MaxValueValidator(MAX_SCOPE, _('The scope for language must be 
from 1 to %d' % MAX_SCOPE))
        ])
    date_added = models.DateTimeField(_('Date aded'), auto_now_add=True)

    # managers
    objects = models.Manager()
    objects = ReplyQuerySet.as_manager()

    # other methods

    def get_total_scope(self):
        return self.__class__.objects.replies_with_total_scope().get(pk=self
.pk).total_scope
    get_total_scope.admin_order_field = 'total_scope'
    get_total_scope.short_description = _('Total scope')


*Custom queryset for model Reply*


from django.db import models

from mylabour.functions_db import Round

class ReplyQuerySet(models.QuerySet):
    """
    QuerySet for replies.
    """

    def replies_with_total_scope(self):
        """Determining average scope for each reply by their scopes: for 
content, for style, for language."""

        # getting total sum all of the scopes
        self = self.annotate(
            sum_scope=models.F('scope_for_content') + models.F(
'scope_for_style') + models.F('scope_for_language')
        )
        # determining avg scope
        self = self.annotate(total_scope=models.ExpressionWrapper(
            models.F('sum_scope') / models.Value(3.0), output_field=models.
FloatField()
        ))
        # make round for avg scope
        self = self.annotate(total_scope=Round('total_scope'))
        return self

Question next.
I need create queryset method to determinate rating of the each book. For 
it, I need have field 'total_scope' for each reply in a model Book.

I am attemped made method in queryset of a model Book and I don`t know have 
solve this problem.

from django.utils import timezone
from django.db import models

from mylabour.functions_db import Round

class BookQuerySet(models.QuerySet):
    """
    Queryset for books.
    """

    def books_with_rating(self):
        """Queryset with rating of each the book."""

        raise NotImplementedError

        # I need have total scope for each reply for using as next:
        # self.annotate(rating=model.Avg('replies__total_scope'))


Welcome any other solutions (supposed using .extra()), but I need rating 
books in my Admin.

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/d1225280-ca1d-415a-aeab-923b15885464%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to