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

Viewed 134

Getting Error while working with ManyToManyField in Django form, this error come while use ManyToManyField in managar field. when i used foreign key with same code its working properly i need to work on manytomanyfield, kindly help me out

models.py

class Team(BaseModel):
    Team_name = models.CharField(max_length=30)
    Logo=models.ImageField(upload_to='img/%Y/%m/%d',height_field=None, width_field=None, max_length=100, default=None)
    Team_manager_photo=models.ImageField(upload_to='img/%Y/%m/%d',null=True, blank=True)
    manager=models.ManyToManyField(User)
    city =models.ForeignKey(
        City,
        models.CASCADE,
        verbose_name='City',
    )
    

form.py this is form for add and edit data

class TeamForm(forms.Form):
    Team_name = forms.CharField(max_length=30,required=True)
    city = forms.ModelChoiceField(required=True, queryset=City.objects.all())
    Logo=forms.ImageField(required=False)
    Team_manager_photo=forms.ImageField(required=False)
    manager= forms.ModelMultipleChoiceField(required=False, queryset=User.objects.all(),widget=forms.SelectMultiple(attrs={'class': 'form-control'}))

    def __init__(self, *args, **kwargs):
        # city_id = kwargs.pop("city_id")
        self.request = kwargs.pop('request', None)
        super(TeamForm, self).__init__(*args, **kwargs)

views.py Function for Add and edit data

def add_edit_team(request, city_id=None, id=None):
    if id:
        team=Team.objects.get(pk=id)
    if request.method == "POST":
        form=TeamForm(request.POST, request.FILES, request=request)
        if form.is_valid():
            Team_name=form.cleaned_data['Team_name']
            Logo=form.cleaned_data['Logo']
            Team_manager_photo=form.cleaned_data['Team_manager_photo']
            manager=form.cleaned_data['manager']
            city=request.POST['city']

            if id:
                team.Team_name=Team_name
                team.Logo=Logo
                team.Team_manager_photo=Team_manager_photo
                team.manager=manager
                team.city_id=city
                team.save()
                messages.success(request,'Team data updated successfully!')
                return redirect('/fleet/team_list')
            else:
                s = Team(Team_name=Team_name,Logo=Logo,Team_manager_photo=Team_manager_photo,manager=manager,city_id = city)
                s.save()
                messages.success(request,'Team data added successfully!')
                return redirect('/fleet/team_list')
    elif id:        
        form=TeamForm(initial={'Team_name':team.Team_name,'Logo':team.Logo,'Team_manager_photo':team.Team_manager_photo,'manager':team.manager,'city':team.city})

    else:
        form=TeamForm()

    context = {
        'menu_car_management': 'active',
        'submenu_team': 'active',
        'form': form,
        'id': id,
        'city_id': city_id,
    }
    return render(request, "hiringprocess/team_edit.html", context=context)

error output while adding new record

ERROR Internal Server Error: /fleet/team/1/add
Traceback (most recent call last):
  File "C:\Users\HI\AppData\Local\Programs\Python\Python37\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
    response = get_response(request)
  File "C:\Users\HI\AppData\Local\Programs\Python\Python37\lib\site-packages\django\core\handlers\base.py", line 115, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "C:\Users\HI\AppData\Local\Programs\Python\Python37\lib\site-packages\django\core\handlers\base.py", line 113, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:\Users\HI\AppData\Local\Programs\Python\Python37\lib\site-packages\django\contrib\auth\decorators.py", line 21, in _wrapped_view
    return view_func(request, *args, **kwargs)
  File "E:\20_jan_2022_everest\everest_jarvis\fleet\views.py", line 3636, in add_edit_team
    s = Team(Team_name=Team_name,Logo=Logo,Team_manager_photo=Team_manager_photo,manager=manager,city_id = city)  
  File "C:\Users\HI\AppData\Local\Programs\Python\Python37\lib\site-packages\django\db\models\base.py", line 496, 
in __init__
    _setattr(self, prop, kwargs[prop])
  File "C:\Users\HI\AppData\Local\Programs\Python\Python37\lib\site-packages\django\db\models\fields\related_descriptors.py", line 538, in __set__
    % self._get_set_deprecation_msg_params(),
TypeError: Direct assignment to the forward side of a many-to-many set is prohibited. Use manager.set() instead.  
ERROR "POST /fleet/team/1/add HTTP/1.1" 500 95625
2 Answers

When using ManyToMany you need to get the User object and then add it to manager field. You can't add an object to ManyToManyField when creating an instance. Have a look at the docs. https://docs.djangoproject.com/en/2.2/topics/db/examples/many_to_many/

def add_edit_team(request, city_id=None, id=None):
    if id:
        team=Team.objects.get(pk=id)
    if request.method == "POST":
        form=TeamForm(request.POST, request.FILES, request=request)
        if form.is_valid():
            Team_name=form.cleaned_data['Team_name']
            Logo=form.cleaned_data['Logo']
            Team_manager_photo=form.cleaned_data['Team_manager_photo']
            manager=form.cleaned_data['manager']
            city=request.POST['city']
           # Am assuming the User model has a manage field, but you can otherwise filter 
           # by any field in the user model.
            managar_of_team = User.objects.filter(manager__in=manager)
            if id:
                team.Team_name=Team_name
                team.Logo=Logo
                team.Team_manager_photo=Team_manager_photo
                team.manager= managar_of_team
                team.city_id=city
                team.save()
                messages.success(request,'Team data updated successfully!')
                return redirect('/fleet/team_list')
            else:
                s = Team(Team_name=Team_name,Logo=Logo,Team_manager_photo=Team_manager_photo,manager= managar_of_team,city_id = city)
                s.save()
                messages.success(request,'Team data added successfully!')
                return redirect('/fleet/team_list')
    elif id:        
        form=TeamForm(initial={'Team_name':team.Team_name,'Logo':team.Logo,'Team_manager_photo':team.Team_manager_photo,'manager':team.manager,'city':team.city})

    else:
        form=TeamForm()

    context = {
        'menu_car_management': 'active',
        'submenu_team': 'active',
        'form': form,
        'id': id,
        'city_id': city_id,
    }
    return render(request, "hiringprocess/team_edit.html", context=context)

If the image and manager(s) are not required, you need to set blank=True on the corresponding model field, and probably it is better to rename manager to managers since that hints that we are working with multiple managers:

from django.conf import settings

class Team(BaseModel):
    # …
    Logo=models.ImageField(upload_to='img/%Y/%m/%d',height_field=None, width_field=None, max_length=100, default=None, blank=True)
    managers = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True)
    # …

I would furthermore advise to work with a ModelForm: a ModelForm can remove a lot of boilerplate code and thus makes the view smaller and easier to implement:

from django import forms

class TeamForm(forms.ModelForm):
    class Meta:
        model = Team
        fields = '__all__'
        widgets = {
            'managers': forms.SelectMultiple(attrs={'class': 'form-control'})
        }

we thus do not need to manually define any form fields: Django will derive the form fields from the Team model.

In that case the view can be rewritten to:

from django.shortcuts import get_object_or_404

def add_edit_team(request, city_id=None, id=None):
    if id is not None:
        team = get_object_or_404(Team, city_id=city_id, pk=id)
    else:
        team = None
    if request.method == 'POST':
        form = TeamForm(request.POST, request.FILES, instance=team)
        if form.is_valid():
            form.save()
            if team is not None:
                messages.success(request,'Team data updated successfully!')
            else:
                messages.success(request,'Team data added successfully!')
            return redirect('/fleet/team_list')
    else:
        form = TeamForm(instance=team)
    context = {
        'menu_car_management': 'active',
        'submenu_team': 'active',
        'form': form,
        'id': id,
        'city_id': city_id,
    }
    return render(request, 'hiringprocess/team_edit.html', context=context)

and that's it: the form will automatically create or update the instance wrapped in the form and make the necessary changes (to the model fields and the many-to-many relation).


Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.

Related