显示来自多个表的数据的最佳方式

时间:2016-07-25 02:40:38

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

我有一个反复出现的问题,我似乎无法充分解决。我的网站类似于工作网站,人们可以在那里发布工作(和详细信息),其他人可以为他们添加书签。显然,每个作业都可以被多个观看者加入书签。

所以这是model.py:

class Job(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    title = models.CharField(max_length=150)
    description = models.CharField(max_length=5000)


class Bookmark(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    job = models.ForeignKey(Job, on_delete=models.CASCADE)

我的目的是在主页中显示所有作业,这意味着来自多个用户的多个作业。其他用户可以单击一个小书签图标来为其添加书签,或者取消对其进行书签。像这样:

这是view.py:

def index(request):
    context = {}
    populateContext(request, context)

    jobs = Job.objects.all().order_by('-id')

    context = {'jobs': jobs}


    return render(request, 'templates/index.html', context)

我觉得很简单,这是我的意图。以下是模板的外观:

{% for job in jobs %}
    <div>
        {{ job.title }}<br>
        {{ job.description }}<br>
        by {{ job.user.username }}
    </div>
{% endfor %}

我的问题是,如何显示特定于每个用户的书签状态?这是我目前的解决方案:

{% for job in jobs %}
    <div>
        {{ job.title }}<br>
        {{ job.description }}<br>
        by {{ job.user.username }}<br>

        {% for watch in job.bookmark_set.all %}
            {% if watch.user_id = request.user.id %}
                You have bookmarked this! <a>Unbookmark!</a>
            {% endif %}
        {% endfor %}

        <a>Bookmark</a>
    </div>
{% endfor %}

“Unbookmark!”顺便说一句,链接将定位在“书签”链接上。上述解决方案以这种方式工作,因为书签表将包含特定作业的零个或多个书签,但在多个用户下。我会在view.py中通过过滤登录用户所做的作业来处理这个问题。但我不能专门过滤哪个工作,因为index.html将全部显示它们。例如,我可以吐出来......:

bookmarked = Bookmark.objects.all().filter(user_id=request.user.id)

...这将列出登录用户所做的不同作业的所有书签。我仍然需要在模板中对其进行过滤,以便每个项目都与每个书签匹配,我理解这是不可能的。

无论如何,我认为这是非常低效的。所以我想知道是否有更简单的方法来处理这个问题?最好是以这种方式工作:

{% for job in jobs %}
    <div>
        {{ job.title }}<br>
        {{ job.description }}<br>
        by {{ job.user.username }}<br>

        {% if job.id = bookmark.job.id %}
            You have bookmarked this! <a>Unbookmark!</a>
        {% else %}
            <a>Bookmark</a>
        {% endif %}
    </div>
{% endfor %}

谢谢!

1 个答案:

答案 0 :(得分:4)

您可以使用conditional expressions使用此信息为jobs添加注释。在视图中:

from django.db.models import Case, IntegerField, Sum, When

jobs = Job.objects.annotate(
           is_bookmarked=Sum(Case(
               When(bookmark__user=request.user, then=1), 
               default=0, output_field=IntegerField()
           ))).order_by('-id')

每个job现在都有is_bookmarked属性,该属性为1(用户为作业添加了书签)或0。在您的模板中:

{% for job in jobs %}
    <div>
        {% if job.is_bookmarked %}
            You have bookmarked this! <a>Unbookmark!</a>
        {% else %}
            <a>Bookmark</a>
        {% endif %}
    </div>
{% endfor %}

为了完整起见,你想到的另一种方法也会起作用(虽然效率低于上面的方法)。在视图中:

jobs = Job.objects.all().order_by('-id')
# Get a list of all Job IDs bookmarked by this user
user_bookmarks = Bookmark.objects.filter(user_id=request.user.id)\
                                 .values_list('job__id', flat=True)

在模板中:

{% for job in jobs %}
    <div>  
        {% if job.id in user_bookmarks %}
            You have bookmarked this! <a>Unbookmark!</a>
        {% else %}
            <a>Bookmark</a>
        {% endif %}
    </div>
{% endfor %}

这两种方法都采用了几乎相同的逻辑 - 不同之处在于第一种方法在数据库级别执行此操作通常更有效。