禁止直接赋值给多对多集合的前端。使用 songs.set() 代替

Direct assignment to the forward side of a many-to-many set is prohibited. Use songs.set() instead

我正在尝试将歌曲添加到我的播放列表模型中,但它一直显示

Direct assignment to the forward side of a many-to-many set is prohibited. Use songs.set() instead. My code for Playlist model:

class Playlist(models.Model):
    image = models.ImageField()
    name = models.CharField(max_length=100)
    artist = models.ForeignKey(User, on_delete=models.CASCADE)
    fav = models.BooleanField(default=False)
    songs = models.ManyToManyField(Music)
    slug = models.SlugField(editable=False, default=name)

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('playlist-detail', kwargs={'pk': self.pk})

    @classmethod
    def add_music(cls, new_song):
        playlist, created = cls.objects.get_or_create(songs=new_song)
        playlist.songs.add(new_song)

    @classmethod
    def remove_music(cls, new_song):
        playlist, created = cls.objects.get_or_create(songs=new_song)
        playlist.songs.remove(new_song)

我的歌曲模型代码:

class Music(models.Model):
    image = models.ImageField()
    name = models.CharField(max_length=100)
    song = models.FileField(upload_to='musics/', blank=False, null=False)
    artist = models.ForeignKey(User, on_delete=models.CASCADE)
    fav = models.BooleanField(default=False)
    slug = models.SlugField(editable=False, default=name)
    lyrics = models.TextField(default="Unknown lyrics")
    genre = models.CharField(
        max_length=2,
        choices=GENRE,
        null=False,
        blank=False,
        default=""
    )

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('post-detail', kwargs={'pk': self.pk})

我的将歌曲添加到播放列表对象的视图方法

def add_to_playlist(request, operation, pk):
    new_song = Music.objects.get(pk=pk)
    if operation == 'add':
        Playlist.add_music(new_song)
    elif operation == 'remove':
        Playlist.remove_music(new_song)
    return redirect('/')

Html代码:

 {% for i in music %}
  {% for v in playlist %}
     <a class="dropdown-item" href="{% url 'add_to_playlist' operation='add' pk=i.pk %}">Add to{{v.name}}</a>
   {% endfor %}  
 {% endfor %}

完整错误:

Traceback:

File "C:\Users\hooriaishtiaq\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\db\models\query.py" in get_or_create
  538.             return self.get(**kwargs), False

File "C:\Users\hooriaishtiaq\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\db\models\query.py" in get
  408.                 self.model._meta.object_name

During handling of the above exception (Playlist matching query does not exist.), another exception occurred:

File "C:\Users\hooriaishtiaq\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\core\handlers\exception.py" in inner
  34.             response = get_response(request)

File "C:\Users\hooriaishtiaq\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\core\handlers\base.py" in _get_response
  115.                 response = self.process_exception_by_middleware(e, request)

File "C:\Users\hooriaishtiaq\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\core\handlers\base.py" in _get_response
  113.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "C:\Users\hooriaishtiaq\workspace\sound\core\views.py" in add_to_playlist
  129.         Playlist.add_music(new_song)

File "C:\Users\hooriaishtiaq\workspace\sound\core\models.py" in add_music
  70.         playlist, created = cls.objects.get_or_create(songs=new_song)

File "C:\Users\hooriaishtiaq\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\db\models\manager.py" in manager_method
  82.                 return getattr(self.get_queryset(), name)(*args, **kwargs)

File "C:\Users\hooriaishtiaq\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\db\models\query.py" in get_or_create
  541.             return self._create_object_from_params(kwargs, params)

File "C:\Users\hooriaishtiaq\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\db\models\query.py" in _create_object_from_params
  575.                 obj = self.create(**params)

File "C:\Users\hooriaishtiaq\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\db\models\query.py" in create
  420.         obj = self.model(**kwargs)

File "C:\Users\hooriaishtiaq\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\db\models\base.py" in __init__
  496.                             _setattr(self, prop, kwargs[prop])

File "C:\Users\hooriaishtiaq\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\db\models\fields\related_descriptors.py" in __set__
  538.             % self._get_set_deprecation_msg_params(),

Exception Type: TypeError at /add_to_playlist/add/11/
Exception Value: Direct assignment to the forward side of a many-to-many set is prohibited. Use songs.set() instead.

我认为你的方法是错误的,因为当你调用 remove_music 时,首先创建新歌曲然后删除??,这不符合逻辑:

@classmethod
    def remove_music(cls, new_song):
        playlist, created = cls.objects.get_or_create(songs=new_song)
        playlist.songs.remove(new_song)

您应该像下面这样在您的方法中添加 try 和 except:

@classmethod
    def remove_music(cls, new_song):
        try:        
            playlist = cls.objects.get(songs=new_song)
            playlist.songs.remove(new_song)
        except cls.DoesNotExist:
            print("Song couldn't removed") # or something

您缺少播放列表 ID:

 <a class="dropdown-item" href="{% url 'add_to_playlist' operation='add' pk=i.pk playlist_id=v.id%}">Add to{{v.name}}</a>

在那种情况下你可以这样做:

def add_to_playlist(request, operation, pk, playlist_id):
    playlist = Playlist.objects.get(pk=playlist_id)
    new_song = Music.objects.get(pk=pk)
    if operation == 'add':
        playlist.songs.add(new_song)
    elif operation == 'remove':
        playlist.songs.remove(new_song)
    return redirect('/')