Home > Net >  Django limit choice of user field foreign key based on the user that logged in
Django limit choice of user field foreign key based on the user that logged in

Time:11-13

I have a model called Client with user field as a foreign key:

class Client(models.Model):
    name = models.CharField(_('Client Name'), max_length=100)
    address = models.CharField(_('Client Address'), max_length=100, blank=True)
    demand = models.PositiveIntegerField(_('Client Demand'))
    location = models.PointField(_('Client Location'))
    created_at = models.DateTimeField(auto_now=True)
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
    )

    class Meta:
        default_permissions = ('add', 'change', 'delete', 'view')

    def __str__(self):
        return self.name

I want to limit the choice of the user field in the admin form based on who logged in

django admin form

for example, here I logged in as agung, so I want the select box choice of user field limit only to agung, but here I can access other username like admin and rizky.

I tried this

class ClientAdminForm(forms.ModelForm):
    class Meta:
        model = Client
        fields = "__all__"


    def __init__(self, request, *args, **kwargs):
        super(ClientAdminForm, self).__init__(request, *args, **kwargs)
        if self.instance:
            self.fields['user'].queryset = request.user

but it seems that it can't take request as an argument (I guess because this is not an Http request)

CodePudding user response:

You can do it by override the base_fields attribute of your form instance like this :

views.py

# Before instantiate the form class
 ClientAdminForm.base_fields['user'] = forms.ModelChoiceField(queryset=self.request.user)

# Now you can instantiate the form
form = ClientAdminForm(...)

NB : Do override the base_fields just before instantiate the form

CodePudding user response:

You can overwrite your Admin Model's get_form method to add the current request.user as class property. Next you can read it in the Form's constructor and filter the query.


class ClientAdmin(admin.ModelAdmin):
    # [...]
    
    def get_form(self, request, obj=None, **kwargs):
        form_class = super(ClientAdmin, self).get_form(request, obj, **kwargs)
        form_class.set_user(request.user)

        return form_class


class ClientAdminForm(forms.ModelForm):
    # [...]

    @classmethod
    def set_user(cls, user):
        cls.__user = user

    def __init__(self, *args, **kwargs):
        super(ClientAdminForm, self).__init__(request, *args, **kwargs)
        if self.instance:
            self.fields['user'].queryset = \
                self.fields['user'].queryset.filter(pk=self.__user.pk)

However, is easiest exclude this field in form and update it in the save_model method:


class ClientAdminForm(forms.ModelForm):
    # [...]
    
    def save_model(self, request, obj, form, change):
        obj.user = request.user
        obj.save()
  • Related