mehdy
mehdy

Reputation: 3374

Django limit the choices of a many to many relationship

I know the title says the question has been asked before but the situation is different.

I have something called Agent:

class Agent(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='agents')
    ...

and a Group:

class Group(models.Model):
    agents = models.ManyToManyField('agents.Agent', blank=True, related_name='groups')

now with Django class based views (UpdateView maybe) I want create a view that a user can see only its agents and select only one of them to add it to a specific group.

as far as I get was this

@method_decorator(login_required, name='dispatch')
class GroupAgentRegister(UpdateView):
    model = Group
    fields = ('agents',)
    template_name = 'register.html'
    context_object_name = 'group'

    def get_form(self, form_class=None):
        form = super(GroupAgentRegister, self).get_form(form_class)
        form.fields['agents'].queryset = self.request.user.agents.all()
        return form

    def form_valid(self, form):
        if self.object.agents.filter(user=self.request.user):
            form.add_error(None, ValidationError(u'Already Registered'))
            return super(GroupAgentRegister, self).form_invalid(form)
        return super(GroupAgentRegister, self).form_valid(form)

the form rendering is fine except that I'm able to select multiple agents. but when I select a value and post it it replace the new selected agents with existing ones and it's not appended to the old ones.

Upvotes: 1

Views: 1933

Answers (1)

mehdy
mehdy

Reputation: 3374

I solved it this way. it may help others too.

first I created a form:

class GroupRegistrationForm(forms.ModelForm):
    agents = forms.ModelChoiceField(Group.objects.none())

    class Meta:
        model = Group
        fields = ('agents',)

and I changed the register view to this:

@method_decorator(login_required, name='dispatch')
class GroupAgentRegister(UpdateView):
    model = Group
    form_class = GroupRegistrationForm
    fields = ('agents',)
    template_name = 'register.html'
    context_object_name = 'group'

    def get_form(self, form_class=None):
        form = super(GroupAgentRegister, self).get_form(form_class)
        form.fields['agents'].queryset = self.request.user.agents.all()
        return form

    def form_valid(self, form):
        if self.object.agents.filter(user=self.request.user):
            form.add_error(None, ValidationError(u'Already Registered'))
            return super(GroupAgentRegister, self).form_invalid(form)
        self.object.agents.add(form.cleaned_data['agents'])
        self.object.save()
        return HttpResponseRedirect(self.get_success_url())

and everything works fine with the most minimal change I had to apply.

Upvotes: 1

Related Questions