7

I'm following the method used by @Yauhen Yakimovich in this question:

do properties work on django model fields?

To have a model field that is a calculation of a different model.

The Problem:

FieldError: Cannot resolve keyword 'rating' into field. Choices are: _rating

The rating model field inst correctly hidden and overridden by my rating property causing an error when I try to access it.

My model:

class Restaurant(models.Model):    
    ...
    ...
    @property
    def rating(self):
        from django.db.models import Avg
        return Review.objects.filter(restaurant=self.id).aggregate(Avg('rating'))['rating__avg']

Model in Yauhen's answer:

class MyModel(models.Model):
    __foo = models.CharField(max_length = 20, db_column='foo')
    bar = models.CharField(max_length = 20)

    @property
    def foo(self):
        if self.bar:
            return self.bar
        else:
            return self.__foo

    @foo.setter
    def foo(self, value):
        self.__foo = value

Any ideas on how to correctly hid the rating field and define the @property technique?

Community
  • 1
  • 1
agconti
  • 17,780
  • 15
  • 80
  • 114
  • 1
    You are trying to set the value inside the getter. Look at the example you posted. You need to provide a getter (decorated with `@property`) and a separate setter (decorated with `@rating.setter`). – BrenBarn Aug 26 '13 at 15:39
  • @BrenBarn What do you mean? I believe I'm not trying to implement the setting functionality, just the get. For example, I just want to be able to call `r.rating` and get back the average. I never want to set `r.rating` as something. I know I'm setting it in the initial `@property` method but that seems correct after following this [question](http://stackoverflow.com/questions/1146a5293/django-model-field-value-is-calculation-of-other-fileds) and others using the same tactic. Also, why would that cause the `FieldError`? – agconti Aug 26 '13 at 15:44
  • The question you linked to in your original question says "properties cannot be used in QuerySet", which means you probably can't use `Avg('rating')`. – BrenBarn Aug 26 '13 at 15:48
  • @BrenBarn: Not probably, but _for sure_. The property is just in the model instance, while query set in this case just takes field/column name. – Tadeck Aug 26 '13 at 15:49
  • @Tadeck: I just say "probably" because I don't know enough about Django to know what that's doing :-) – BrenBarn Aug 26 '13 at 15:50

2 Answers2

4

Solved by using sorted()

I was using a query with order_by() to call rating. order_by() is at the database level and doesnt know about my property. Soultion, use Python to sort instead:

sorted(Restaurant.objects.filter(category=category[0]), key=lambda x: x.rating, reverse=True)[:5]

If you encounter a similar error check through your views for anything that might be calling the property. Properties will no longer work at the datatbase level.

agconti
  • 17,780
  • 15
  • 80
  • 114
1

Change this line:

self._rating = Review.objects.filter(restaurant=self.id).aggregate(Avg('rating'))['rating__avg']

into this one:

self._rating = Review.objects.filter(restaurant=self.id).aggregate(Avg('_rating'))['_rating__avg']

(notice change of reference in query from rating and rating__avg to _rating and _rating__avg)

Tadeck
  • 132,510
  • 28
  • 152
  • 198
  • I used your solution to get rid of the `FieldError`, but it comes right back once the property is called. For example: `Restaurant.objects.filter(category=category[0]).order_by('_rating')[:5]` returns only none types and forces me to change the @proprety Avg('_rating'))['_rating__avg'] to Avg('rating'))['rating__avg'] to avoid the field error. Am I properly tyring to query the property? – agconti Aug 26 '13 at 16:09
  • I am not sure I follow. Are you saying changing the code from your version to mine fixes `FieldError`, but you need to change it back to fix `FieldError`? Well, think about your property as if it was a function (because it is, it is a getter - in Java it would be called `getRating()`). There is also a column storing the results of that calculation. You can perform a query based on the column, but you cannot do it based on the Python function (at least not on the database level). Could you post examples of what you have tried, and results? – Tadeck Aug 26 '13 at 16:18