Django: How to get current user in admin forms

后端 未结 6 1705
花落未央
花落未央 2020-11-30 00:31

In Django\'s ModelAdmin I need to display forms customized according to the permissions an user has. Is there a way of getting the current user object into the form class, s

相关标签:
6条回答
  • 2020-11-30 00:59

    Joshmaker's answer doesn't work for me on Django 1.7. Here is what I had to do for Django 1.7:

    class BlogPostAdmin(admin.ModelAdmin):
        form = BlogPostForm
    
        def get_form(self, request, obj=None, **kwargs):
            form = super(BlogPostAdmin, self).get_form(request, obj, **kwargs)
            form.current_user = request.user
            return form
    

    For more details on this method, please see this relevant Django documentation

    0 讨论(0)
  • 2020-11-30 00:59

    stumbled upon same thing and this was first google result on my page.Dint helped, bit more googling and worked!!

    Here is how it works for me (django 1.7+) :

    class SomeAdmin(admin.ModelAdmin):
        # This is important to have because this provides the
        # "request" object to "clean" method
        def get_form(self, request, obj=None, **kwargs):
            form = super(SomeAdmin, self).get_form(request, obj=obj, **kwargs)
            form.request = request
            return form
    
    class SomeAdminForm(forms.ModelForm):
        class Meta(object):
            model = SomeModel
            fields = ["A", "B"]
    
        def clean(self):
            cleaned_data = super(SomeAdminForm, self).clean()
            logged_in_email = self.request.user.email #voila
            if logged_in_email in ['abc@abc.com']:
                raise ValidationError("Please behave, you are not authorised.....Thank you!!")
            return cleaned_data
    
    0 讨论(0)
  • 2020-11-30 01:01

    Another way you can solve this issue is by using Django currying which is a bit cleaner than just attaching the request object to the form model.

    from django.utils.functional import curry
    
    class BlogPostAdmin(admin.ModelAdmin):
        form = BlogPostForm
    
        def get_form(self, request, **kwargs):
            form = super(BlogPostAdmin, self).get_form(request, **kwargs)
            return curry(form, current_user=request.user)
    

    This has the added benefit making your init method on your form a bit more clear as others will understand that it's being passed as a kwarg and not just randomly attached attribute to the class object before initialization.

    class BlogPostForm(forms.ModelForm):
    
       def __init__(self, *args, **kwargs):
           self.current_user = kwargs.pop('current_user')
           super(BlogPostForm, self).__init__(*args, **kwargs)
    
    0 讨论(0)
  • 2020-11-30 01:02

    This use case is documented at ModelAdmin.get_form

    [...] if you wanted to offer additional fields to superusers, you could swap in a different base form like so:

    class MyModelAdmin(admin.ModelAdmin):
        def get_form(self, request, obj=None, **kwargs):
            if request.user.is_superuser:
                kwargs['form'] = MySuperuserForm
            return super().get_form(request, obj, **kwargs)
    

    If you just need to save a field, then you could just override ModelAdmin.save_model

    from django.contrib import admin
    
    class ArticleAdmin(admin.ModelAdmin):
        def save_model(self, request, obj, form, change):
            obj.user = request.user
            super().save_model(request, obj, form, change)
    
    0 讨论(0)
  • 2020-11-30 01:03

    I think I found a solution that works for me: To create a ModelForm Django uses the admin's formfield_for_db_field-method as a callback.
    So I have overwritten this method in my admin and pass the current user object as an attribute with every field (which is probably not the most efficient but appears cleaner to me than using threadlocals:

        def formfield_for_dbfield(self, db_field, **kwargs):
            field = super(MyAdmin, self).formfield_for_dbfield(db_field, **kwargs)
            field.user = kwargs.get('request', None).user
            return field
    

    Now I can access the current user object in the forms __init__ with something like:

        current_user=self.fields['fieldname'].user
    
    0 讨论(0)
  • 2020-11-30 01:12

    Here is what i did recently for a Blog:

    class BlogPostAdmin(admin.ModelAdmin):
        form = BlogPostForm
    
        def get_form(self, request, **kwargs):
             form = super(BlogPostAdmin, self).get_form(request, **kwargs)
             form.current_user = request.user
             return form
    

    I can now access the current user in my forms.ModelForm by accessing self.current_user

    EDIT: This is an old answer, and looking at it recently I realized the get_form method should be amended to be:

        def get_form(self, request, *args, **kwargs):
             form = super(BlogPostAdmin, self).get_form(request, *args, **kwargs)
             form.current_user = request.user
             return form
    

    (Note the addition of *args)

    0 讨论(0)
提交回复
热议问题