【问题标题】:'<' not supported between instances of 'method' and 'method' - Python, Django在“方法”和“方法”的实例之间不支持“<”-Python、Django
【发布时间】:2018-08-20 11:32:59
【问题描述】:

我正在尝试做 Winerama Recommender Tutorial 。我遇到了一个我无法解决的错误。当我尝试转到“推荐列表”选项卡时,浏览器返回以下错误。

错误

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'

我根据教程中的步骤创建了所有内容。

文件 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()])

接下来我添加了 admin.py 并在“/admin”中创建了 3 个 klaster。

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)

我的文件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}
    )

我会标记,当我尝试使用简单版本时,一切正常。

@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}
    )

我的错误在于本教程的stage (2.5)。 2.4 阶段效果很好。 一切都表明views.py 中有问题。

任何帮助将不胜感激。

【问题讨论】:

  • 看起来average_rating 是一个函数不是一个属性/属性。可以分享Wine 模型吗?
  • 当然,上面我已经添加了整个models.py文件
  • 这是一个糟糕的教程;作者似乎不知道如何进行跨模型查询。所有这些重复的 set/map/lambda 东西都没有理由。例如,“简单版”中的那个可以只替换为Wine.objects.exclude(review__user_name=request.user.username)。但另外评论应该有一个用户的外键,而不是将用户名存储为一个 CharField。真的,你应该找到更好的教程。
  • 另请注意,User.objects.get(username=request.user.username) 只是浪费处理器周期和开发人员的大脑时间 - request.user 是同一个对象。
  • 感谢您的评论,我将不得不做一个更好的教程。也许你听说过一些类似的好教程(这意味着,展示机器学习是如何工作的)?我也会在网上搜索后添加一些有趣的链接。

标签: python django


【解决方案1】:

sorted() 函数接受返回值的函数key。似乎 x.average_rating 是方法,而不是值。所以你有2个选择

  • 在 x.average_rating 之后添加 ()
  • 将 x.average_rating 转换为 property

【讨论】:

  • 或者,也许更优雅的是,当你已经有一个函数时,根本不使用 lambda:key=Wine.average_rating
  • 非常感谢,当然添加 'add () po x.average_rating' 解决了整个问题。
【解决方案2】:

方法和方法返回的值是有区别的。在您的Wine 模型中,我们看到:

from django.db.models import Avg

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

    def average_rating(self):
        return self.review_set.aggregate(
            mean=Avg('rating')
        )['mean']

    def __unicode__(self):
        return self.name

(我重写了它以进行高效查询,而不是 Python/Django/Numpy 让我们来做这项工作)。

如果您现在有一个名为some_wineWine 对象,那么您不会在此处使用some_wine.average_rating 获得平均评分,因为这将返回一个方法,但通过调用该函数,所以some_wine.average_rating<b>()</b>

这里有一些选项:

  1. lambda 表达式中调用函数

    wine_list = sorted(
        list(Wine.objects.filter(id__in=other_users_reviews_wine_ids)),
        key=lambda x: x.average_rating(),
        reverse=True
    )
  2. 把方法定义为一个属性,这样的话,你就不再调用这个函数了,它是在幕后被调用的,所以:

    from django.db.models import Avg
    
    class Wine(models.Model):
      name = models.CharField(max_length=200)
    
      @property
      def average_rating(self):
          return self.review_set.aggregate(
              mean=Avg('rating')
          )['mean']
    
      def __unicode__(self):
          return self.name
  3. 使用Wine.average_rating 作为键,从那时起它是一个调用实例的函数:

    wine_list = sorted(
        list(Wine.objects.filter(id__in=other_users_reviews_wine_ids)),
        key=Wine.average_rating,
        reverse=True
    )
  4. 排序Wine对象已经被数据库,使用.annotate(..)

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

最新的方法可能是最有效的,因为数据库通常针对此类查询进行了优化,此外,这将通过单个查询来完成。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-12
    • 2017-09-14
    • 1970-01-01
    • 2020-02-12
    相关资源
    最近更新 更多