Я создал класс 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)
Я надеюсь, что кто-то найдет время, чтобы помочь мне с моей проблемой. Спасибо заранее.
Ваше среднее значение также не является действительным средним значением. Вы каждый раз делите avg
на два? Это значит, что последний комментарий вносит вклад в 50%, предпоследний — 25%, следующий за ним — 12,5% и т. д.
Можешь поделиться своей Comment
моделью?
Вы не можете фильтровать, аннотировать или объединять свойства или методы. Свойства и методы определены в модели 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)
Вы не можете фильтровать функции или свойства. Набор запросов транслируется в запрос к базе данных, а база данных ничего не знает о свойствах или методах.