[Answered ]-Limit Django ModelForm ForeignKey choices depending on request.user

1πŸ‘

I do this by overriding CreateView.get_form_class() in order to modify the attributes of the relevant field of the form before it is passed to the rest of the view.

The default method, inherited from views.generic.edit.ModelFormMixin, returns a ModelForm that represents all the editable fields of the model in the base_fields dictionary. So it’s a good place to make any desired changes and also has access to self.request.user.

So for the above example, in views.py we might say:

class ContentCreateView(LoginRequiredMixin, CreateView):
    model = Content
    fields = '__all__'

    def get_form_class(self):
        modelform = super().get_form_class()
        modelform.base_fields['folder'].limit_choices_to = {'user': self.request.user}
        return modelform

Read more about ForeignKey.limit_choices_to in the docs.

Note that field choices are enforced by form validation so this should be quite robust.

πŸ‘€Martin CR

0πŸ‘

The following mixin looks automatically limits the choices for all foreign key fields that point to a model that has a user field:

class LimitForeignKeyChoicesToSameUserMixin:

    def get_form_class(self):
        this_model_has_user_field = False
        choice_limited_fields = []
        for field in self.model._meta.get_fields():
            if isinstance(field, ForeignKey) or isinstance(field, ManyToManyField):
                if field.name == 'user':
                    this_model_has_user_field = True
                elif hasattr(field.related_model, 'user'):
                    choice_limited_fields.append(field.name)
        form_class = super().get_form_class()
        if this_model_has_user_field:
            for field in choice_limited_fields:
                form_class.base_fields[field].limit_choices_to = {'user': self.request.user}
        return form_class  

And then I use the following base class for all β€˜add’ views:

class AddViewBase(LoginRequiredMixin, LimitForeignKeyChoicesToSameUserMixin, 
                  CreateView, FormMixin):
    slug_url_kwarg = 'id'
    slug_field = 'id'

    def form_valid(self, form):
        form.instance.user = self.request.user
        return super().form_valid(form)

And this base class for β€˜edit’ views:


class EditViewBase(LoginRequiredMixin, LimitForeignKeyChoicesToSameUserMixin,
                   UpdateView):
    slug_url_kwarg = 'id'
    slug_field = 'id'
πŸ‘€Bruno Rijsman

Leave a comment