简体   繁体   中英

'<' not supported between instances of 'method' and 'method' - Python, Django

I'm trying to do Winerama Recommender Tutorial . I met a error which I can't solve. When I try to go to the tab 'recommendation list' the browser returned the following error.

Error

Environment:


Request Method: GET
Request URL: http://127.0.0.1:8000/recommendation/

Django Version: 2.0.7
Python Version: 3.7.0
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'bootstrap3',
 'reviews',
 'registration']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']



Traceback:

File "C:\Users\tymot\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\core\handlers\exception.py" in inner
  35.             response = get_response(request)

File "C:\Users\tymot\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\core\handlers\base.py" in _get_response
  128.                 response = self.process_exception_by_middleware(e, request)

File "C:\Users\tymot\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\core\handlers\base.py" in _get_response
  126.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "C:\Users\tymot\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\contrib\auth\decorators.py" in _wrapped_view
  21.                 return view_func(request, *args, **kwargs)

File "C:\Users\tymot\Desktop\Cd-12.50-20.08\env\my_app\winerama\reviews\views.py" in user_recommendation_list
  89.         reverse=True

Exception Type: TypeError at /recommendation/
Exception Value: '<' not supported between instances of 'method' and 'method'

I created everything according to the steps in the tutorial.

File models.py

from django.db import models
from django.contrib.auth.models import User
import numpy as np


class Wine(models.Model):
    name = models.CharField(max_length=200)

    def average_rating(self):
        all_ratings = [list(map(lambda x: x.rating, self.review_set.all()))]
        return np.mean(all_ratings)

    def __unicode__(self):
        return self.name


class Review(models.Model):
    RATING_CHOICES = (
        (1, '1'),
        (2, '2'),
        (3, '3'),
        (4, '4'),
        (5, '5'),
    )
    wine = models.ForeignKey(Wine, on_delete=models.CASCADE)
    pub_date = models.DateTimeField('date published')
    user_name = models.CharField(max_length=100)
    comment = models.CharField(max_length=200)
    rating = models.IntegerField(choices=RATING_CHOICES)

class Cluster(models.Model):
    name = models.CharField(max_length=100)
    users = models.ManyToManyField(User)

    def get_members(self):
        return "\n".join([u.username for u in self.users.all()])

Next i added admin.py and create 3 klaster with users in '/admin'.

from django.contrib import admin

from .models import Wine, Review, Cluster

class ReviewAdmin(admin.ModelAdmin):
    model = Review
    list_display = ('wine', 'rating', 'user_name', 'comment', 'pub_date')
    list_filter = ['pub_date', 'user_name']
    search_fields = ['comment']


class ClusterAdmin(admin.ModelAdmin):
    model = Cluster
    list_display = ['name', 'get_members']


admin.site.register(Wine)
admin.site.register(Review, ReviewAdmin)
admin.site.register(Cluster, ClusterAdmin)

My file views.py

@login_required
def user_recommendation_list(request):
    # get request user reviewed wines
    user_reviews = Review.objects.filter(user_name=request.user.username).prefetch_related('wine')
    user_reviews_wine_ids = set(map(lambda x: x.wine.id, user_reviews))

    # get request user cluster name (just the first one righ now)
    user_cluster_name = \
        User.objects.get(username=request.user.username).cluster_set.first().name

    # get usernames for other memebers of the cluster
    user_cluster_other_members = \
        Cluster.objects.get(name=user_cluster_name).users \
            .exclude(username=request.user.username).all()
    other_members_usernames = set(map(lambda x: x.username, user_cluster_other_members))

    # get reviews by those users, excluding wines reviewed by the request user
    other_users_reviews = \
        Review.objects.filter(user_name__in=other_members_usernames) \
            .exclude(wine__id__in=user_reviews_wine_ids)
    other_users_reviews_wine_ids = set(map(lambda x: x.wine.id, other_users_reviews))

    # then get a wine list including the previous IDs, order by rating
    wine_list = sorted(
        list(Wine.objects.filter(id__in=other_users_reviews_wine_ids)),
        key=lambda x: x.average_rating,
        reverse=True
    )

    return render(
        request,
        'reviews/user_recommendation_list.html',
        {'username': request.user.username, 'wine_list': wine_list}
    )

I will mark that when I try use simple version everything works fine.

@login_required
def user_recommendation_list(request):
    # get this user reviews
    user_reviews = Review.objects.filter(user_name=request.user.username).prefetch_related('wine')
    # from the reviews, get a set of wine IDs
    user_reviews_wine_ids = set(map(lambda x: x.wine.id, user_reviews))
    # then get a wine list excluding the previous IDs
    wine_list = Wine.objects.exclude(id__in=user_reviews_wine_ids)

    return render(
        request,
        'reviews/user_recommendation_list.html',
        {'username': request.user.username,'wine_list': wine_list}
    )

My error is at this stage (2.5) of the tutorial. Stage 2.4 works good. Everything indicates that something is wrong in views.py.

Any help will be very appreciated.

The sorted() function accepts function key that returns value. Seems like x.average_rating is method, not the value. So you have 2 choices

  • add () after x.average_rating
  • convert x.average_rating to property

There is a difference between a method and the value a method returns. Here in your Wine model, we see:

from django.db.models import 

class Wine(models.Model):
    name = models.CharField(max_length=200)

    :
        return self.review_set.aggregate(
            mean=
        )['mean']

    def __unicode__(self):
        return self.name

(I rewrote it to make an efficienty query, instead of Python/Django/Numpy let do the work).

If you now have a Wine object named some_wine , then you do not get the average rating here with some_wine.average_rating , since this will return a method, but by calling the function, so some_wine.average_rating .

There are some options here:

  1. calling the function in the lambda expression :

     wine_list = sorted( list(Wine.objects.filter(id__in=other_users_reviews_wine_ids)), key=lambda x: x.average_rating  , reverse=True ) 
  2. define the method as a property, in that case, you no longer call the function, it is the called behind the curtains, so:

     from django.db.models import  class Wine(models.Model): name = models.CharField(max_length=200)  def average_rating(self): return self.review_set.aggregate( mean=  )['mean'] def __unicode__(self): return self.name 
  3. use Wine.average_rating as key, since then it is a function that is called with instances:

     wine_list = sorted( list(Wine.objects.filter(id__in=other_users_reviews_wine_ids)), key=  , reverse=True ) 
  4. order the Wine objects already by the database, by using .annotate(..) :

     wine_list = Wine.objects.filter( id__in=other_users_reviews_wine_ids ).annotate( mean=Avg('rating') ).order_by('-rating') 

The latest approach is probably the most efficient, since a database typically is optimized for such queries, furthermore this will get done by a single query.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM