【问题标题】:'NoneType' object has no attribute 'name'“NoneType”对象没有属性“名称”
【发布时间】:2017-06-28 14:12:51
【问题描述】:

我正在尝试建立一个葡萄酒推荐系统。在reviews/view.py 页面我收到了这个错误:

'NoneType' object has no attribute 'name'

这是我得到这些错误的那一行

User.objects.get(username=request.user.username).cluster_set.first().name 

完整代码如下:

from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from django.contrib.auth.models import User
from .models import Review, Wine, Cluster
from .forms import ReviewForm
from .suggestions import update_clusters

import datetime

from django.contrib.auth.decorators import login_required


def review_list(request):
    latest_review_list = Review.objects.order_by('-pub_date')[:9]
    context = {'latest_review_list': latest_review_list}
    return render(request, 'reviews/review_list.html', context)


def review_detail(request, review_id):
    review = get_object_or_404(Review, pk=review_id)
    return render(request, 'reviews/review_detail.html', {'review': review})


def wine_list(request):
    wine_list = Wine.objects.order_by('-name')
    context = {'wine_list': wine_list}
    return render(request, 'reviews/wine_list.html', context)


def wine_detail(request, wine_id):
    wine = get_object_or_404(Wine, pk=wine_id)
    form = ReviewForm()
    return render(request, 'reviews/wine_detail.html', {'wine': wine, 'form': form})


@login_required
def add_review(request, wine_id):
    wine = get_object_or_404(Wine, pk=wine_id)
    form = ReviewForm(request.POST)
    if form.is_valid():
        rating = form.cleaned_data['rating']
        comment = form.cleaned_data['comment']
        user_name = request.user.username
        review = Review()
        review.wine = wine
        review.user_name = user_name
        review.rating = rating
        review.comment = comment
        review.pub_date = datetime.datetime.now()
        review.save()
        update_clusters()
        # Always return an HttpResponseRedirect after successfully dealing
        # with POST data. This prevents data from being posted twice if a
        # user hits the Back button.
        return HttpResponseRedirect(reverse('reviews:wine_detail', args=(wine.id,)))

    return render(request, 'reviews/wine_detail.html', {'wine': wine, 'form': form})


def user_review_list(request, username=None):
    if not username:
        username = request.user.username
    latest_review_list = Review.objects.filter(user_name=username).order_by('-pub_date')
    context = {'latest_review_list': latest_review_list, 'username': username}
    return render(request, 'reviews/user_review_list.html', context)


@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)
    try:
        user_cluster_name = \
            User.objects.get(username=request.user.username).cluster_set.first().name
    except:  # if no cluster has been assigned for a user, update clusters
        update_clusters()
        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}
    )

【问题讨论】:

  • 之前忘记贴update_cluster函数了,在回答部分有提到。你能不能帮我复习一下。

标签: django python-3.x recommendation-engine


【解决方案1】:

update_clusters 方法中的代码很可能没有为用户创建集群。确保您实际上是在为特定用户创建集群对象。如果仍有疑问,也请提及该函数的代码。

【讨论】:

  • 我已经发布了 update_cluster 函数的代码......知道哪里出错了吗?
【解决方案2】:

cluster_set 为空。在尝试使用它之前,您应该检查该变量是否不等于 None。

【讨论】:

    【解决方案3】:

    这里是 update_cluster() 的代码

    def update_clusters():
        num_reviews = Review.objects.count()
        update_step = ((num_reviews / 100) + 1) * 5
        if num_reviews % update_step == 0:  # using some magic numbers here, sorry...
            # Create a sparse matrix from user reviews
            all_user_names = map(lambda x: x.username, User.objects.only("username"))
            all_wine_ids = set(map(lambda x: x.wine.id, Review.objects.only("wine")))
            num_users = len(all_user_names)
            ratings_m = dok_matrix((num_users, max(all_wine_ids) + 1), dtype=np.float32)
            for i in range(num_users):  # each user corresponds to a row, in the order of all_user_names
                user_reviews = Review.objects.filter(user_name=all_user_names[i])
                for user_review in user_reviews:
                    ratings_m[i, user_review.wine.id] = user_review.rating
    
            # Perform kmeans clustering
            k = int(num_users / 10) + 2
            kmeans = KMeans(n_clusters=k)
            clustering = kmeans.fit(ratings_m.tocsr())
    
            # Update clusters
            Cluster.objects.all().delete()
            new_clusters = {i: Cluster(name=i) for i in range(k)}
            for cluster in new_clusters.values():  # clusters need to be saved before refering to users
                cluster.save()
            for i, cluster_label in enumerate(clustering.labels_):
                new_clusters[cluster_label].users.add(User.objects.get(username=all_user_names[i]))
    

    【讨论】:

    • 您应该将其作为问题本身的一部分,而不是答案。
    • 嗯,我很抱歉,但我忘了提早...你还能帮忙
    • 虽然您的代码很难提出任何有用的建议,但您似乎只是将用户添加到集群中 k 次,即 - (int(num_users / 10) + 2)。所以你最终根本没有将你想要的用户与任何集群相关联。
    • 不管你之前有没有提到过,你应该编辑你的问题并添加到那里。
    猜你喜欢
    • 2015-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-30
    • 1970-01-01
    • 2021-11-02
    • 2014-07-05
    • 2018-05-05
    相关资源
    最近更新 更多