Я хочу отфильтровать функцию def 'getAmountRating(self):'

Я создал класс Restaurant, в котором вы можете найти функцию 'def getAmountRating(self):'. Эта функция должна использоваться как ключевое слово в моем файле django_filter.

class Restaurant(models.Model):
restaurant_picture = models.ImageField(null=True, default='dashboard-BG.jpg')
name = models.CharField(max_length=200, null=True)

address = models.CharField(max_length=128, blank=True)
houseNumber = models.IntegerField(default=1)

city = models.CharField(max_length=64, default = "")
state = models.CharField(max_length=64, default = "")
zip_code = models.CharField(max_length=5, default = "86444")

tags = models.ManyToManyField(Tag)
affordability = models.FloatField(validators=[MaxValueValidator(3), MinValueValidator(1)], null=True)
objects = models.Manager()

def getAverageRating(self):
    comments = Comment.objects.all()
    avg = 0
    count = 0
    for i in comments:
        if i.restaurant == self:
            avg += i.ratings
            if count is 0:
                count += 1
            else:
                avg = avg / 2
    if avg is not 0:
        avg = round(avg)
    return avg

В фильтре

class RestaurantFilter(django_filters.FilterSet):

rating = NumberFilter(field_name = "getAverageRating", lookup_expr = "gte")

class Meta:
    model = Restaurant
    fields = '__all__'
    exclude = ['location', 'restaurant_picture', 'address', 'houseNumber', 'state']

Мне уже пришлось признать, что это не работает так, как хотелось бы.

В качестве исправления я искал некоторые решения, но эти решения не работали. Например, я создал другой класс, содержащий функцию def getAverageRating, и сослался на этот класс в ресторане как - AverageRating = RestaurantRating(), что не сработало.

Я не думаю, что это актуально, но вот views.py

def restaurants(request):
restaurants = Restaurant.objects.all()

foods = Food.objects.all()
comments = Comment.objects.all()

myFilter = RestaurantFilter(request.GET, queryset=restaurants)
restaurants = myFilter.qs

context = {'restaurants': restaurants, 'myFilter': myFilter, 'foods': foods, 'comments': comments}
return render(request, 'accounts/restaurants.html', context)

Я надеюсь, что кто-то найдет время, чтобы помочь мне с моей проблемой. Спасибо заранее.

Вы не можете фильтровать функции или свойства. Набор запросов транслируется в запрос к базе данных, а база данных ничего не знает о свойствах или методах.

Willem Van Onsem 13.12.2020 23:16

Ваше среднее значение также не является действительным средним значением. Вы каждый раз делите avg на два? Это значит, что последний комментарий вносит вклад в 50%, предпоследний — 25%, следующий за ним — 12,5% и т. д.

Willem Van Onsem 13.12.2020 23:17

Можешь поделиться своей Comment моделью?

Willem Van Onsem 13.12.2020 23:21
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
82
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы не можете фильтровать, аннотировать или объединять свойства или методы. Свойства и методы определены в модели Python/Django, но база данных ничего о них не знает. Поскольку Queryset преобразуются в запросы к базе данных, использование метода свойства не имеет особого смысла.

В любом случае, если бы это было возможно, это было бы неэффективно. Это означало бы, что вы извлекаете все Restaurant из памяти, а затем фильтруете каждый ресторан на уровне Python/Django. Python не идеален для фильтрации огромных объемов данных, базы данных предназначены для этого.

Однако нам это не нужно. База данных может сама определять среднее значение связанного поля. Он имеет агрегаты и может группироваться, чтобы получить среднее значение для ресторана. В SQL вы бы построили запрос, например:

SELECT restaurant.*, AVG(comment.rating)
FROM restaurant
LEFT OUTER JOIN comment ON comment.restaurant_id = restaurant.id
GROUP BY restaurant.id

вы можете сделать это и с Django. Действительно, мы можем .annotate(…) [Django-doc] рестораны со средним рейтингом ресторанов с:

from django.db.models import Avg

Restaurant.objects.annotate(
    avg_rating=Avg('comment__ratings')
)

Мы можем использовать это в нашем FilterSet с:

class RestaurantFilter(django_filters.FilterSet):
    rating = NumberFilter(field_name='avg_rating', lookup_expr='gte')
    class Meta:
        model = Restaurant
        exclude = [
            'location'
          , 'restaurant_picture'
          , 'address'
          , 'houseNumber'
          , 'state'
          ]

и в представлении мы, таким образом, можем фильтровать с помощью:

from django.db.models import Avg

def restaurants(request):
    restaurants = Restaurant.objects.annotate(
        avg_rating=Avg('comment__ratings')
    )

    foods = Food.objects.all()
    comments = Comment.objects.all()

    myFilter = RestaurantFilter(request.GET, queryset=restaurants)
    restaurants = myFilter.qs

    context = {'restaurants': restaurants, 'myFilter': myFilter, 'foods': foods, 'comments': comments}
    return render(request, 'accounts/restaurants.html', context)

Другие вопросы по теме