2

I have one model UserSong which has two m2m fields with models Genre and Language

class UserSong(models.Model):
    title           = models.CharField(max_length=100)
    song_file       = models.FileField(upload_to=user_song_directory_path, validators=[validate_audio_file_extension])
    genre           = models.ManyToManyField(Genre)
    language        = models.ManyToManyField(Language)

Genre class is

class Genre(models.Model):
    name            = models.CharField(max_length=255)
    created_date    = models.DateTimeField(auto_now_add=True)
    updated_date    = models.DateTimeField(auto_now=True)
    status          = models.BooleanField(default=False)

Language class is

class Language(models.Model):
    name            = models.CharField(max_length=255)
    created_date    = models.DateTimeField(auto_now_add=True)
    updated_date    = models.DateTimeField(auto_now=True)
    status          = models.BooleanField(default=False)

I am trying to add m2m fields in UserSong object as

genre_name_list =  Genre.objects.filter(name__in=self.cleaned_data['genre'].values_list('name',flat=True))
        # instance.genre.add(*genre_name_list)
        instance.genre.set(genre_name_list)

language_name_list =  Language.objects.filter(name__in=self.cleaned_data['language'].values_list('name',flat=True))
        # instance.language.add(*language_name_list)
        instance.language.set(language_name_list)

The problem here lies is , m2m table is getting updated as it should but still Django is giving me error Direct assignment to the forward side of a many-to-many set is prohibited. Use language.set() instead.

StackTrace

form.cleaned_data['genre'] <class 'genre.models.Genre'>
artist received is  <QuerySet [<UserProfile: Pragya Nagpal>]>
Internal Server Error: /users/5/25/edit_music
Traceback (most recent call last):
  File "/usr/lib/python3.5/site-packages/django/core/handlers/exception.py", line 35, in inner
    response = get_response(request)
  File "/usr/lib/python3.5/site-packages/django/core/handlers/base.py", line 128, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/usr/lib/python3.5/site-packages/django/core/handlers/base.py", line 126, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/lib/python3.5/site-packages/django/contrib/auth/decorators.py", line 21, in _wrapped_view
    return view_func(request, *args, **kwargs)
  File "/usr/lib/python3.5/site-packages/django/contrib/auth/decorators.py", line 21, in _wrapped_view
    return view_func(request, *args, **kwargs)
  File "/root/new_songdew_store/songdewUser/views.py", line 833, in add_edit_music
    status=model_instance.status)
  File "/usr/lib/python3.5/site-packages/django/db/models/manager.py", line 82, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/usr/lib/python3.5/site-packages/django/db/models/query.py", line 415, in create
    obj = self.model(**kwargs)
  File "/usr/lib/python3.5/site-packages/django/db/models/base.py", line 490, in __init__
    _setattr(self, prop, kwargs[prop])
  File "/usr/lib/python3.5/site-packages/django/db/models/fields/related_descriptors.py", line 509, in __set__
    % self._get_set_deprecation_msg_params(),
TypeError: Direct assignment to the forward side of a many-to-many set is prohibited. Use language.set() instead.
Alasdair
  • 298,606
  • 55
  • 578
  • 516
angrysumit
  • 221
  • 4
  • 16
  • Your code using `.set(...)` looks ok. Are you sure it is that code that is causing the error. Make sure you have saved/deployed that code and restarted the server, and include the full traceback in your question. – Alasdair Sep 26 '18 at 13:05
  • @Alasdair , I am having a hard time finding this. As you said, I think it works alright because I have similar models `UserVideo` and `Album` and they do the same. Strange thing is, this is in development server and was tested fair enough. But now only this model is throwing error, not others. P.S error `use language.set() instead` sometimes changes with `use genre.set() instead`. – angrysumit Sep 26 '18 at 13:11
  • The `form.cleaned_data` in your question suggests that the error is happening earlier when you save the form. The traceback will show you exactly where the error is occurring. – Alasdair Sep 26 '18 at 13:12
  • @Alasdair I double checked it. Ignoring `self.cleaned_data['genre']` type (its already a queryset, so using `set(self.cleaned_data['genre'])` would work too), stacktrace does not give any useful information. – angrysumit Sep 26 '18 at 13:16
  • and by god ways, m2m table is still being updated. funny enough to cry out loud – angrysumit Sep 26 '18 at 13:17
  • Please show the full `add_edit_music` view. – Alasdair Sep 26 '18 at 13:48
  • @Alasdair https://ideone.com/9zs8v1 please look at it – angrysumit Sep 26 '18 at 16:33

1 Answers1

7

The traceback shows you that the error is occuring in the product_item = Product.objects.create() call. You need to create the instance first, then set the values for any many-to-many fields:

product_item = Product.objects.create(...)
product_item.genre.set(...)
Alasdair
  • 298,606
  • 55
  • 578
  • 516
  • thats the benefit of third eye view – angrysumit Sep 26 '18 at 16:39
  • 1
    Make sure you read the traceback carefully so you can be sure you are looking in the right part of your code. Because the `Product.objects.create(...)` call is over multiple lines, the traceback shows `status=model_instance.status` which isn't very useful, but if you use the line numbers (or even search for `status=model_instance.status` in your code), you'll see where the problem is. – Alasdair Sep 26 '18 at 16:42
  • thanks, I also had to delete the list field of dict because had a empty list assigned – Francisco Rodeño Sanchez Feb 14 '20 at 20:36