【问题标题】:Model method or custom template filter模型方法或自定义模板过滤器
【发布时间】:2013-10-27 18:01:15
【问题描述】:

我的问题是我需要知道用户是否对某个模型实例 BlogSite 进行了评分。在页面上,有多个 BlogSite 实例,它们具有 5 星评级系统。当前用户对某个实例进行评分后,应设置为只读。

我遇到了障碍,因为如果我使用模型函数,我需要传递 2 个变量 - current_user 和 BlogSite。我一直无法在 models.py 中找到如何访问 request.user 并且看起来我不应该这样做?

我走的另一条路是创建一个自定义过滤器 - 但我发现我只能传入一个参数。我宁愿不这样做,因为我觉得将逻辑保留在views.py中会更好

有人知道我该如何解决这个问题吗?

#models.py
class BlogSite(models.Model):
    #fields

#get the average rating for a blogsite
def rating_avg(self):
    rating_dict = BlogSiteReview.objects.filter(blog_site=self).aggregate(Avg('review_rating'))
    rating_avg = rating_dict.get('review_rating__avg')
    if rating_avg:
        return rating_avg
    else:
        #no ratings
        return 0

def rated(self, current_user):
    #If there is a row for the blogsitereview with this blogsite for the logged in user, return True, else False
    #can I access the current user? This does not work, seems like I can't get request here.
    current_user = request.user
    review = BlogSiteReview.objects.filter(blog_site=self, user=current_user)

    if review:
        return True
    else:
        return False

class BlogSiteReview(models.Model):
    blog_site = models.ForeignKey(BlogSite)
    user = models.ForeignKey(User)
    #other fields

这是视图的相关部分:

#views.py
def search(request, type, regionValue):
    #....
    #ideally, the solution would be to have a field or function in the BlogSite model
    blog_sites = BlogSite.objects.filter(country=region.id, active=True)
    #....

在模板中,如果评级返回 True,我将有一个 if 语句来添加一个类

<tr>
    <td><a href="http://{{ blogsite.url }}" id="{{ blogsite.id }}">{{ blogsite.site_name }}</a></td>
    <td><div id="rating{{ blogsite.id }}" class="rating {% if blogsite.user_rated %}jDisabled{% endif %}" data-average="{{ blogsite.rating_avg }}" data-id="{{ blogsite.id }}"></div></td>
    <td>{{ blogsite.create_date }}</td>
</tr>

我在这里寻找两件事 - 使用模型方法来获取用户是否评分似乎是正确的方法?到目前为止,我遇到的问题是我找不到如何访问当前用户以在 models.py 中使用。我想到的另一个想法是以某种方式从视图中传入 request.current_user ,但用户与 BlogSite 没有关联,所以我无法对其进行过滤。

【问题讨论】:

    标签: python django django-models django-templates django-views


    【解决方案1】:

    我最终采取了一种稍微不同的方法,这是我在试图入睡时想到的,但我无法摆脱 Django :) 在视图中,我创建了某个用户留下评论的 blog_sites 列表

    #views.py
    rated = BlogSiteReview.objects.filter(user=request.user).values_list('blog_site', flat=True)
    return render(request, page, {..., 'blogsites':blog_sites, 'rated':rated})
    

    如果 blog_site FK id 在 blog_sites for 循环中,我在模板中添加了一个类:

    #template
    {% for blogsite in blogsites %}
    <tr>
      <td><a href="http://{{ blogsite.url }}" id="{{ blogsite.id }}">{{ blogsite.site_name }}</a></td>
      <td><div id="rating{{ blogsite.id }}" class="rating {% if blogsite.id in rated %}jDisabled{% endif %}" data-average="{{ blogsite.rating_avg }}" data-id="{{ blogsite.id }}"></div></td>
      <td>{{ blogsite.create_date }}</td>
      <td>{{ rated }}</td>
    </tr>
    {% empty %}
      <p>There are no registered blogsites for this country.</p>
    {% endfor %}
    

    我终于可以睡觉了!

    【讨论】:

      【解决方案2】:

      您可以通过模板参数传递blog_site.rated(request.user) 的结果。如果您为模板提供多个 BlogSite 实例(视图示例中的 blog_sites)并在模板中迭代它们,您可以将实例和 rated 结果分组到视图中的元组或字典中,如下所示:

      ({"site": block_site, "rated": block_site.rated(request.user)} for block_site in block_sites)
      

      并在模板中分别使用result.siteresult.rated 访问它们,假设result 是模板中的迭代变量(因为您将视图命名为search)(替换模板中的blogsite sn-p)。

      因此,我个人会保留您发布的 rated 方法,并使用 current_user 参数。

      编辑:这是一个混合了您的代码(问题和答案)和我的建议的示例:

      #views.py
      def search(request, type, regionValue):
          #....
          blog_sites = BlogSite.objects.filter(country=region.id, active=True)
          search_results = ({"site": block_site, "rated": block_site.rated(request.user)} for block_site in block_sites)
          return render(request, page, {..., 'search_results': search_results})
      

      在模板中:

      {% for result in search_results %}
        {% with blogsite=result.site rated=result.rated %}
          <tr>
            <td><a href="http://{{ blogsite.url }}" id="{{ blogsite.id }}">{{ result.site.site_name }}</a></td>
            <td><div id="rating{{ blogsite.id }}" class="rating {% if rated %}jDisabled{% endif %}" data-average="{{ blogsite.rating_avg }}" data-id="{{ blogsite.id }}"></div></td>
            <td>{{ blogsite.create_date }}</td>
            <td>{{ rated }}</td>
          </tr>
        {% endwith %}
      {% empty %}
        <p>There are no registered blogsites for this country.</p>
      {% endfor %}
      

      【讨论】:

      • 为了完整起见,我根据您的问答源代码添加了代码示例,以说明我打算做什么。但是,您的方法(在您自己的答案中)可能更有效,因为它只涉及一个 DB 查询来获取评级的博客网站,而不是通过评级方法对每个博客网站进行一次查询。
      猜你喜欢
      • 2014-02-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-13
      • 2011-05-28
      • 2011-03-29
      • 2012-08-19
      • 2017-03-05
      • 2017-02-10
      相关资源
      最近更新 更多