Django ManyToManyField在数据库中的位置/位置如何? [英] Where/how is Django ManyToManyField represented in the database?

查看:38
本文介绍了Django ManyToManyField在数据库中的位置/位置如何?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

<强> 更新: 只要发现该ManyToManyField导致当选择了特定相册管理界面崩溃.我把它们注释掉了,注释掉了所有引用,重新运行了 makemigrations migrate ,现在管理界面又可以工作了……这使我离实现此目标还差得远收藏夹"列的工作:(请参阅此跟进:函数执行此连接.视图的 get_queryset()中当前正在运行的查询是

 返回超级(专辑列表,自身).get_queryset().order_by("pub_date") 

(下面完整的 views.py .)我目前的猜测是:

return super(AlbumList,self).get_queryset().order_by("pub_date").extra(select = {"is_favorite":"favorited_by_users__id =" + str(request.user.id)})

但是,尽管这不会崩溃,但是模板中每个 {{is_favorite}} 的值是 nothing (空字符串).这是有道理的,因为数据库中还没有任何东西,但是现在呢?我不知道这是否是正确的Django查询.

我想在数据库中添加一个项目对此进行测试,并使用postgres中的手动SQL语句(尚不通过Django命令),但是我该如何以及在何处执行此操作?

我已经成功运行了 makemigrations ,然后使用此新的m2m列(并且没有 FavoriteSongs 模型)进行了 migration ,但是我什么也没看到在数据库中代表is-favorite的值. billyjoel_album 中没有多余的列,也没有类似于 billyjoel_favoritealbum 的穿透表.那么,这些数据在哪里/如何存储在数据库中?

(有关此收藏夹"专栏的其他建议也将得到赞赏!)

谢谢.


models.py

django.db导入模型中的

 从django.contrib.auth.models导入用户从进口时间开始def get_upload_file_name(实例,文件名):返回"uploaded_files/%s_%s"%(str(time()).replace(.","_"),文件名)类Album(models.Model):职务=(("J",主要工作室发行"),(我",非主要官方版本"),("U",非官方"),)标题= models.CharField(max_length = 70)description = models.TextField(max_length = 500,default =",null = True,blank = True)pub_date = models.DateField('发布日期')官僚主义= models.CharField(max_length = 1,choices = OFFICIALITY)is_concert = models.BooleanField(默认= False)main_info_url = models.URLField(blank = False)thumbnail = models.FileField(upload_to = get_upload_file_name,blank = True,null = True)#virtual字段可跳过穿透表.歌曲=模型.ManyToManyField("Song",通过="AlbumSong")favoritedby_users = models.ManyToManyField(用户)def __str __():返回self.title类Meta:#默认顺序为发布日期(升序).订购= ['pub_date']Song类(models.Model):名称= models.CharField(max_length = 100)description = models.TextField(max_length = 500,default =",null = True,blank = True)length_seconds = models.IntegerField()lyrics_url = models.URLField(default =",blank = True,null = True)专辑=模型.ManyToManyField(专辑",通过="AlbumSong")favoritedby_users = models.ManyToManyField(用户)def get_length_desc_from_seconds(self):if(self.length_seconds == -1):返回"-1"m,s = divmod(self.length_seconds,60)h,m = divmod(m,60)如果(h):返回%d:%02d:%02d"%(h,m,s)别的:返回%d:%02d"%(m,s)def __str __():返回self.name类AlbumSong(models.Model):歌曲=模型.ForeignKey(歌曲)专辑=模型.ForeignKey(专辑)sequence_num = models.IntegerField()类Meta:unique_together =('相册','sequence_num',)unique_together =('专辑','歌曲',)def __str __():返回str(self.album)+:" + str(self.sequence_num)+:" + str(self.song) 

views.py

来自.models的

 导入专辑,歌曲,专辑歌曲从datetime导入datetime,timedelta从django.core.context_processors导入csrf从django.shortcuts导入渲染,render_to_response从django.views.generic导入DetailView,ListView从枚举导入枚举def get_str_with_appended(string,between_if_str_non_empty,new_value):if(len(string)== 0):返回new_value别的:返回字符串+ between_if_str_non_empty + new_valuePrependQuestionMark(Enum)类:是,否=范围(2)def get_url_param_string_from_params(prepend_question_mark = PrependQuestionMark.YES,** kwargs_all_params):param_list ="输入iter(kwargs_all_params)中的密钥:值= kwargs_all_params [key]if(值不为None):param_list = get_str_with_appended(param_list,'&',str(key)+"=" + str(value))if(len(param_list)== 0):返回param_list;if(prepend_question_mark == PrependQuestionMark.YES):返回  "?"+ param_list别的:返回param_list类AlbumList(ListView):模特=专辑context_object_name =相册"#源自irc/#dango/tbaxter ... STARTdef dispatch(self,request,* args,** kwargs):#默认为ascself.sort_order = request.GET.get("sort_order",无)self.sort_item = request.GET.get("sort_item",无)self.csrf_token = csrf(request)["csrf_token"]self.logged_in_user = request.user#self.csrf_token = request.GET.get("csrf_token",无)返回super(AlbumList,self).dispatch(request,* args,** kwargs)def get_queryset(self):两者中的#Item均为零#应该是静态全局asc_desc_list = ["asc","dsc"]sort_by_types = ["pub_date","title"]if(self.sort_order为None且self.sort_item为None):#使用默认顺序返回super(AlbumList,self).get_queryset()#自定义订购sort_order = self.sort_ordersort_item = self.sort_item如果(sort_order为None或sort_order不在asc_desc_list中):sort_order = asc_desc_list [0]如果(sort_item为None或sort_item不在sort_by_types中):sort_item = sort_by_types [0]order_minus =",如果sort_order =="asc",否则为-"返回super(AlbumList,self).get_queryset().order_by(order_minus + sort_item).extra(select = {"is_favorite":"favorited_by_users__id =" + str(self.logged_in_user.id)})def get_context_data(self,** kwargs):context =超级(AlbumList,self).get_context_data(** kwargs)context ["sort_order"] = self.sort_ordercontext ["sort_item"] = self.sort_itemcontext ["url_params"] = get_url_param_string_from_params(sort_item = self.sort_item,sort_order = self.sort_order,csrf_token = self.csrf_token)返回上下文类AlbumDetail(DetailView):模特=专辑context_object_name =专辑"def dispatch(self,request,* args,** kwargs):#默认为ascself.sort_order = request.GET.get("sort_order",无)self.sort_item = request.GET.get("sort_item",无)self.csrf_token = csrf(request)["csrf_token"]返回super(AlbumDetail,self).dispatch(request,* args,** kwargs)def get_context_data(self,** kwargs):#首先调用基本实现以获取上下文context = super(AlbumDetail,self).get_context_data(** kwargs)#添加所需的额外信息:album_songs,排序方式为#sequence_num#select_related是一次在数据库中查询所有歌曲#在视图中,以防止模板对数据库进行针刺#在每个for循环迭代中.对于大型数据集,这是至关重要的.context ['album_songs'] = kwargs ["object"].albumsong_set.order_by('sequence_num').select_related("song")context ["url_params"] = get_url_param_string_from_params(sort_item = self.sort_item,sort_order = self.sort_order,csrf_token = self.csrf_token)返回上下文 

album_list.html

  {%扩展了"base.html"%}{%load bj_filters%}{%标题%} Billy Joel专辑浏览器{%endblock%}{%block sidebar%}< UL>< LI>< a href ="{%url'album_list'%} {{url_params}}">所有相册</A></LI>< LI>< a href ="/admin/"> Admin</A></LI></UL>{%endblock%}{%封锁内容%}< TABLE ALIGN ="center" WIDTH ="100%" BORDER ="1" CELLSPACING ="0" CELLPADDING ="4" BGCOLOR =#EEEEEE">< TR ALIGN ="center" VALIGN ="middle">{%如果user.is_authenticated%}< TD>我的个人资料(< a href ="{%url'accounts_logout'%}">注销</A>)</TD>{% 别的 %}< TD>< a href ="{%url'accounts_login'%}">登录</A>查看您的收藏夹</TD>{% 万一 %}</TR></TABLE>< H1>比利·乔尔专辑浏览器</H1><!-< P> url_params = {{url_params}}</P>->{%,如果albums.count>0%}< P>官方:< IMG SRC ="/static/images/major.jpg" height ="20"/> =主要工作室发行,< IMG SRC ="/static/images/minor.jpg"高度="20"/> =正式发布,< IMG SRC ="/static/images/unofficial.jpg" height ="20"/> = Unofficial</P>< TABLE ALIGN ="center" WIDTH ="100%" BORDER ="1" CELLSPACING ="0" CELLPADDING ="4" BGCOLOR =#EEEEEE">< TR ALIGN ="center" VALIGN ="middle">< TD>< B>< U>< a href ="{%url'album_list'%}?sort_item = title& sort_order ={%如果sort_item =='pub_date'%} asc {%else%}{{sort_order | multival_to_str:'asc,dsc-> dsc,asc,dsc'}}{% 万一 %}& csrf_token = {{csrf_token}}>标题</A</U></B>< BR>< I>< FONT SIZE ="-1>(单击标题以查看其歌曲列表).< TD>< B>< U>< a href ="{%url'album_list'%}?sort_item = pub_date& sort_order ={%if sort_item =='title'%} asc {%else%}{{sort_order | multival_to_str:'asc,dsc-> dsc,asc,dsc'}}{% 万一 %}& csrf_token = {{csrf_token}}>已发布</A>/U</B</TD>< TD>官方</TD>< TD>音乐会</TD>< TD> Wiki</TD>< TD>最喜欢的</TD>{%代表专辑中专辑的%}< ;!-专辑"后没有冒号-></TR>< TR>< TD VALIGN ="top">{%if album.thumbnail%}< img src ="/static/{{album.thumbnail}}" width ="25"/>{% 别的 %}< img src ="/static/images/white_block.jpg" width ="25"/>{% 万一 %}& nbsp;< a href ="/albums/get/{{album.id}} {{url_params}}"> {{album.title}}</a>{%如果为album.description%}< BR/>< FONT SIZE =-1">< I> {{album.description | truncatewords:10}}</I</FONT>{% 万一 %}< TD> {{album.pub_date | date:"m/y"}}</TD>< TD>< IMG SRC ="/static/images/{{album.officiality | multival_to_str:" J,I,U->主要,次要,非官方,残破的图像}}.jpg" height ="20"/></TD>< TD> {{album.is_concert | yesno:是,否"}}</TD>< TD>< A HREF ="{{album.main_info_url}}"> Wiki</A</TD>< TD< I> n/a {{is_favorite}}</I</TD>{%endfor%}</TR></TABLE>{% 别的 %}< P< I>数据库中没有相册.{% 万一 %}{%endblock%} 

解决方案

在数据库中,完全中表示多对多字段的方式与原始FavouriteSongs模型相同-链接带有歌曲"和用户"的ForeignKey的表.摆脱FavouriteSongs的唯一好处是,您现在使用的是自动定义的穿透表,而不是手动的表.

我不理解您的示例查询,因为您没有说实际调用的是什么模型,或者是什么 self.logged_in_user .但是,您不能像这样使用 extra :您试图在其中放置Django查询语法,并使用双下划线名称来遍历关系,但是 extra 是直接传递的到SQL,那对该语法一无所知.

我不会在一个查询中尝试执行此操作.取而代之的是,我将进行两个查询,一个查询获取所有专辑,另一个查询获取用户的收藏夹. get_queryset 只会返回完整的专辑列表,然后您可以使用 get_context_data 获得代表收藏夹ID的其他对象集:

 收藏夹= self.logged_in_user.album_set.all().values_list('id',flat = True)context ['favorites'] = set(favorites) 

values_list仅获取相册的ID,因为这是我们所需的全部,然后将它们放入集合中以使查找更快.

现在,您可以在模板中执行以下操作:

  {%代表专辑中的专辑%}...< td> {%,如果相簿收藏夹中的album.id为%}是{%else%}否{%endif%}</td>{%endfor%} 

UPDATE: Just found out that the ManyToManyField is causing the admin interface to crash, when a specific album is selected. I commented them out, commented out all references to it, reran makemigrations and migrate, and now the admin interface works again...which leaves me even farther away from making this "favorite" column work   :( See this followup: Why is Django ManyToManyField causing admin interface to crash? Why is no through table being created?


Background: My goal is to make the "Favorite?" column in this webpage reflect the favorite albums of the currently-logged-in user, where each is either "no" or "yes", and is a clickable link to toggle the choice. (When not logged in, they will all be grey "n/a"-s.)

Therefore, for each album, there may be exactly zero or one "has favorited" entry per user. If the entry exists, they've favorited it. If it doesn't exist, they didn't.

Here is my Album model, with the favorited_by_users many-to-many column (full models.py at the bottom):

class Album(models.Model):
    OFFICIALITY = (
        ('J', 'Major studio release'),
        ('I', 'Non-major official release'),
        ('U', 'Unofficial'),
    )
    title = models.CharField(max_length=70)
    description = models.TextField(max_length=500, default="", null=True, blank=True)
    pub_date = models.DateField('release date')
    officiality = models.CharField(max_length=1, choices=OFFICIALITY)
    is_concert = models.BooleanField(default=False)
    main_info_url = models.URLField(blank=False)
    thumbnail = models.FileField(upload_to=get_upload_file_name, blank=True, null=True)

    #virtual field to skip over the through table.
    songs = models.ManyToManyField("Song", through="AlbumSong")

    favorited_by_users = models.ManyToManyField(User)

    def __str__(self):
        return  self.title

    class Meta:
        #Default ordering is by release date, ascending.
        ordering = ['pub_date']

I originally had this FavoriteAlbum model, but since it has no extra information beyond the foreign keys, it was recommended that I eliminate it in favor of the above many-to-many column.

class FavoriteSongs(models.Model):
    user = models.ForeignKey(User)
    song = models.ForeignKey(Song)

    class Meta:
        unique_together = ('user', 'song',)

    def __str__(self):
        return  "user=" + str(self.user) + ", song=" + str(self.song)

What I need to do is a "left join" between album and user, where all albums are selected, and any favorites by the currently-logged-in user are joined to it (None if they haven't favorited it). I don't know what to do.

I've also been told about the extra() function to do this join. The currently-working query in the view's get_queryset() is

return  super(AlbumList, self).get_queryset().order_by("pub_date")

(Full views.py below.) My current guess is this:

return super(AlbumList, self).get_queryset().order_by("pub_date").extra(select={"is_favorite": "favorited_by_users__id = " + str(request.user.id) })

But, while this doesn't crash, the value of each {{ is_favorite }} in the template is nothing (the empty string). This makes sense since there's nothing in the database yet, but what now? I have no idea if this is the correct Django query.

I want to add an item in the database to test this, with a manual SQL statement in postgres (not via a Django command yet), but how and where do I do this?

I've successfully run makemigrations and then migrate with this new m2m column (and without the FavoriteSongs model), but I see nothing in the database that represents the is-favorite value. There's no extra column in billyjoel_album, and no through table akin to billyjoel_favoritealbum. So where/how is this data stored in the database?

(Any other advice regarding this extra "favorite" column would be appreciated as well!)

Thanks.


models.py

from  django.db import models
from  django.contrib.auth.models import User
from  time import time

def get_upload_file_name(instance, filename):
    return  "uploaded_files/%s_%s" % (str(time()).replace(".", "_"), filename)

class Album(models.Model):
    OFFICIALITY = (
        ('J', 'Major studio release'),
        ('I', 'Non-major official release'),
        ('U', 'Unofficial'),
    )
    title = models.CharField(max_length=70)
    description = models.TextField(max_length=500, default="", null=True, blank=True)
    pub_date = models.DateField('release date')
    officiality = models.CharField(max_length=1, choices=OFFICIALITY)
    is_concert = models.BooleanField(default=False)
    main_info_url = models.URLField(blank=False)
    thumbnail = models.FileField(upload_to=get_upload_file_name, blank=True, null=True)

    #virtual field to skip over the through table.
    songs = models.ManyToManyField("Song", through="AlbumSong")

    favorited_by_users = models.ManyToManyField(User)

    def __str__(self):
        return  self.title

    class Meta:
        #Default ordering is by release date, ascending.
        ordering = ['pub_date']


class Song(models.Model):
    name = models.CharField(max_length=100)
    description = models.TextField(max_length=500, default="", null=True, blank=True)
    length_seconds = models.IntegerField()
    lyrics_url = models.URLField(default="", blank=True, null=True)
    albums = models.ManyToManyField("Album", through="AlbumSong")

    favorited_by_users = models.ManyToManyField(User)

    def get_length_desc_from_seconds(self):
        if(self.length_seconds == -1):
            return  "-1"
        m, s = divmod(self.length_seconds, 60)
        h, m = divmod(m, 60)
        if(h):
            return  "%d:%02d:%02d" % (h, m, s)
        else:
            return  "%d:%02d" % (m, s)

    def __str__(self):
        return  self.name

class AlbumSong(models.Model):
    song = models.ForeignKey(Song)
    album = models.ForeignKey(Album)
    sequence_num = models.IntegerField()

    class Meta:
        unique_together = ('album', 'sequence_num',)
        unique_together = ('album', 'song',)

    def __str__(self):
        return  str(self.album) + ": " + str(self.sequence_num) + ": " + str(self.song)

views.py

from  .models import Album, Song, AlbumSong
from  datetime import datetime, timedelta
from  django.core.context_processors import csrf
from  django.shortcuts import render, render_to_response
from  django.views.generic import DetailView, ListView
from  enum import Enum

def get_str_with_appended(string, between_if_str_non_empty, new_value):
    if(len(string) == 0):
        return  new_value
    else:
        return  string + between_if_str_non_empty + new_value

class PrependQuestionMark(Enum):
    YES, NO = range(2)

def get_url_param_string_from_params(prepend_question_mark=PrependQuestionMark.YES, **kwargs_all_params):
    param_list = ""
    for  key in iter(kwargs_all_params):
        value = kwargs_all_params[key]
        if(value is not None):
            param_list = get_str_with_appended(param_list, '&', str(key) + "=" + str(value))

    if(len(param_list) == 0):
        return  param_list;

    if(prepend_question_mark == PrependQuestionMark.YES):
        return  "?" + param_list
    else:
        return  param_list

class AlbumList(ListView):
    model = Album
    context_object_name = "albums"

    #Derived from irc/#dango/tbaxter...START
    def dispatch(self, request, *args, **kwargs):
                                             #default to asc
        self.sort_order = request.GET.get("sort_order", None)
        self.sort_item = request.GET.get("sort_item", None)
        self.csrf_token = csrf(request)["csrf_token"]
        self.logged_in_user = request.user

        #self.csrf_token = request.GET.get("csrf_token", None)
        return super(AlbumList, self).dispatch(request, *args, **kwargs)

    def get_queryset(self):
        #Item zero in both is the default
        #should be static global
        asc_desc_list = ["asc", "dsc"]
        sort_by_types = ["pub_date", "title"]

        if(self.sort_order is None  and  self.sort_item is None):
            #Use default ordering
            return  super(AlbumList, self).get_queryset()

        #Custom ordering requested

        sort_order = self.sort_order
        sort_item = self.sort_item

        if(sort_order is None  or
                sort_order not in asc_desc_list):
            sort_order = asc_desc_list[0]
        if(sort_item is None  or
                sort_item not in sort_by_types):
            sort_item = sort_by_types[0]

        order_minus = ""  if  sort_order == "asc"  else "-"

        return  super(AlbumList, self).get_queryset().order_by(order_minus + sort_item).extra(select={"is_favorite": "favorited_by_users__id = " + str(self.logged_in_user.id) })

    def get_context_data(self, **kwargs):
        context = super(AlbumList, self).get_context_data(**kwargs)

        context["sort_order"] = self.sort_order
        context["sort_item"] = self.sort_item

        context["url_params"] = get_url_param_string_from_params(
            sort_item=self.sort_item,
            sort_order=self.sort_order,
            csrf_token=self.csrf_token)

        return  context


class AlbumDetail(DetailView):
    model = Album
    context_object_name = "album"

    def dispatch(self, request, *args, **kwargs):
                                             #default to asc
        self.sort_order = request.GET.get("sort_order", None)
        self.sort_item = request.GET.get("sort_item", None)
        self.csrf_token = csrf(request)["csrf_token"]

        return super(AlbumDetail, self).dispatch(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        #Call the base implementation first to get a context
        context = super(AlbumDetail, self).get_context_data(**kwargs)

        #Add in the required extra info: album_songs, ordered by
        #sequence_num

        #select_related is to query the database for all songs at once, here
        #in the view, to prevent the template from pin-pricking the database
        #in each for loop iteration. For large datasets, this is critical.
        context['album_songs'] = kwargs["object"].albumsong_set.order_by('sequence_num').select_related("song")

        context["url_params"] = get_url_param_string_from_params(
            sort_item=self.sort_item,
            sort_order=self.sort_order,
            csrf_token=self.csrf_token)

        return  context

album_list.html

 {% extends "base.html" %}
 {% load bj_filters %}
 {% block title %}Billy Joel Album Browser{% endblock %}

 {% block sidebar %}
 <UL>
  <LI><a href="{% url 'album_list' %}{{ url_params }}">All albums</A></LI>
  <LI><a href="/admin/">Admin</A></LI>
 </UL>
 {% endblock %}

 {% block content %}

 <TABLE ALIGN="center" WIDTH="100%" BORDER="1" CELLSPACING="0" CELLPADDING="4" BGCOLOR="#EEEEEE"><TR ALIGN="center" VALIGN="middle">
 {% if  user.is_authenticated %}
  <TD>My profile (<a href="{% url 'accounts_logout' %}">Logout</A>)</TD>
 {% else %}
  <TD><a href="{% url 'accounts_login' %}">Login</A> to view your favorites</TD>
 {% endif %}
 </TR></TABLE>

 <H1>Billy Joel Album Browser</H1>

 <!--
 <P>url_params={{ url_params }}</P>
  -->

 {% if  albums.count > 0 %}
  <P>Officiality: <IMG SRC="/static/images/major.jpg" height="20"/>=Major studio release, <IMG SRC="/static/images/minor.jpg" height="20"/>=Official release, <IMG SRC="/static/images/unofficial.jpg" height="20"/>=Unofficial</P>
  <TABLE ALIGN="center" WIDTH="100%" BORDER="1" CELLSPACING="0" CELLPADDING="4" BGCOLOR="#EEEEEE"><TR ALIGN="center" VALIGN="middle">
     <TD><B><U><a href="{% url 'album_list' %}?sort_item=title&sort_order=
        {% if  sort_item == 'pub_date' %}asc{% else %}
           {{ sort_order|multival_to_str:'asc,dsc->dsc,asc,dsc' }}
        {% endif %}
     &csrf_token={{ csrf_token }}">Title</A></U></B><BR><I><FONT SIZE="-1">(click a title to view its song list)</FONT></I></TD>
     <TD><B><U><a href="{% url 'album_list' %}?sort_item=pub_date&sort_order=
        {% if  sort_item == 'title' %}asc{% else %}
           {{ sort_order|multival_to_str:'asc,dsc->dsc,asc,dsc' }}
        {% endif %}
     &csrf_token={{ csrf_token }}">Released</A></U></B></TD>
     <TD>Officiality</TD>
     <TD>Concert</TD>
     <TD>Wiki</TD>
     <TD>Favorite?</TD>
  {% for  album in albums %} <!-- No colon after "albums" -->
  </TR><TR>
     <TD VALIGN="top">
        {% if  album.thumbnail %}
           <img src="/static/{{ album.thumbnail }}" width="25"/>
        {% else %}
           <img src="/static/images/white_block.jpg" width="25"/>
        {% endif %}
        &nbsp; <a href="/albums/get/{{ album.id }}{{ url_params }}">{{ album.title }}</a>
        {% if  album.description %}
           <BR/><FONT SIZE="-1"><I>{{ album.description|truncatewords:10 }}</I></FONT>
        {% endif %}
     <TD>{{ album.pub_date|date:"m/y" }}</TD>
     <TD><IMG SRC="/static/images/{{ album.officiality|multival_to_str:"J,I,U->major,minor,unofficial,broken_image"}}.jpg" height="20"/></TD>
     <TD>{{ album.is_concert|yesno:"Yes,No" }}</TD>
     <TD><A HREF="{{ album.main_info_url }}">Wiki</A></TD>
     <TD><I>n/a {{ is_favorite }}</I></TD>
  {% endfor %}
  </TR></TABLE>
 {% else %}
  <P><I>There are no albums in the database.</I></P>
 {% endif %}

 {% endblock %}

解决方案

The many-to-many field is represented in the database in exactly the same way as your original FavouriteSongs model - as a linking table with ForeignKeys to both Song and User. The only benefit of getting rid of FavouriteSongs is that you're now using an automatically-defined through table, rather than a manual one.

I don't understand your example query, since you don't say what model you are actually calling it on, or what self.logged_in_user is. However, you can't use extra like this: you are trying to put Django query syntax there, complete with double-underscore names to traverse relationships, but extra is passed directly to the SQL, and that doesn't know anything about that syntax.

I would not attempt to do this in one query. Instead I would do two queries, one to get all the albums and one to get the user's favourites. get_queryset would just return the full album list, and then you can use get_context_data to get an additional set of objects representing the IDs of the favourites:

favorites = self.logged_in_user.album_set.all().values_list('id', flat=True)
context['favorites'] = set(favorites)

The values_list just gets the IDs of the albums only, since that's all we need, and we then put them into a set to make lookups quicker.

Now, in the template, you can just do:

{% for album in albums %}
    ...
    <td>{% if album.id in favorites %}Yes{% else %}No{% endif %}</td>
{% endfor %}

这篇关于Django ManyToManyField在数据库中的位置/位置如何?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆