0

I'm trying to add a song to the playlist model that I have but it keeps saying

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)

My code for Song model:

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})

my view method that adds the song to the playlist object

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 code:

 {% 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 %}

Full error:

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.

Hic
  • 15
  • 4
  • 6
    The title of your question is totally different than the error you mention. What's the correct error you're trying to resolve? Also, please show us the entire stack trace of your error, it's not clear where the error is happening. – dirkgroten Nov 26 '19 at 13:16
  • Refer: https://stackoverflow.com/questions/50015204/direct-assignment-to-the-forward-side-of-a-many-to-many-set-is-prohibited-use-e – Shubham Rath Nov 26 '19 at 13:17

2 Answers2

0

I think your method is wrong because when you call remove_music, firstly you create new song and after remove??, It's not logic:

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

You should add try and except on your method like below:

@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
Burak Ibis
  • 443
  • 4
  • 13
0

Here you lack the Playlist id:

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

In that case you can do:

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('/')
Sergey Pugach
  • 5,561
  • 1
  • 16
  • 31