Django 根据登录用户限制用户字段外键的选择

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

我有一个名为 Client 的模型,其中用户字段作为外键:

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

我想根据登录者限制管理表单中用户字段的选择

例如,我在这里登录为 agung,所以我希望 select 框选择用户字段限制为 agung,但在这里我可以访问其他用户名,如 admin 和 rizky。

我试过了

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

但是好像不能接受request作为参数(我猜是因为这不是Http请求)

您可以通过重写表单实例的 base_fields 属性来实现,如下所示:

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(...)

注意: 在实例化表单之前重写 base_fields

您可以覆盖管理模型的 get_form 方法以将当前 request.user 添加为 class 属性。接下来您可以在表单的构造函数中读取它并过滤查询。


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__(*args, **kwargs)
        self.fields['user'].queryset = \
            self.fields['user'].queryset.filter(pk=self.__user.pk)

但是,最简单的方法是在表单中排除此字段并在 save_model 方法中更新它:


class ClientAdmin(admin.ModelAdmin):
    # [...]
    
    def save_model(self, request, obj, form, change):
        obj.user = request.user
        obj.save()