Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django auth - Adding user fields - displaying in admin

I'm a complete n00b to django & python. I come from a PHP background so you'll have to accept my apologies for that :p.

I'm trying to use the admin panel functionality in django to show different options to different people.

The system should allow admins to add "projects" to a list. "Developers" should then be able to view only projects assigned to them, and only change certain fields.

So I guess the question is two fold:

1) Is allowing the "Developers" to login to the admin system the best method of doing it?

1.a) If so, How do I get a boolean field to display on the admin's user form? I just want to flag is_developer. I've added it as a userProfile but don't understand how to make it display on the form

2) Should I disallow them to login (to the admin panel) and make "frontend" whereby they can only see what they're allowed?

I hope that made sense. I'm a bit all over the place at the moment as it's a complete departure to what i'm used to!

Thanks in advance for any help you can offer me :)

like image 439
Xenocide Avatar asked Aug 02 '12 19:08

Xenocide


People also ask

Can we customize Django admin panel?

The Django admin is a powerful built-in tool giving you the ability to create, update, and delete objects in your database using a web interface. You can customize the Django admin to do almost anything you want.

What is Fieldsets in Django admin?

It's just a way for you to be able to group the fields on a Model Admin Page. Just implement the example in the documentation and it should become apparent for you.


1 Answers

There's a lot going on here, so I'm going to piecemeal my answer.

Is allowing the "Developers" to login to the admin system the best method of doing it?

That depends on your setup. Generally, the admin should only be available to "staff": people that are employed by or directly related to your organization. In fact, in order to login to the admin, a user must have is_staff=True. If all of the users belong to your organization (and can be considered "trusted" as a result), then yes, it's fine to allow them to all access the admin. Otherwise, it's not a good idea, as you're opening yourself up to security risks.

If so, How do I get a boolean field to display on the admin's user form?

In the most simplistic sense, you can add a field to a form by literally adding it to the form class, even if it's a ModelForm which pre-populates its fields from the fields on the model.

class MyModelForm(forms.ModelForm):
    class Meta:
        model = MyModel

    is_developer = forms.BooleanField(default=False)

I've added it as a userProfile but don't understand how to make it display on the form

UserProfile is a different model, obviously, so its fields are not made available on a form for a User. However, Django does provide the ability to add/edit related models inline with edit form for another model. This is done through inline formsets. In the admin, these are just called "inlines".

class UserProfileInlineAdmin(admin.StackedInline):
    model = UserProfile
    max_num = 1
    can_delete = False

class UserAdmin(admin.ModelAdmin):
    inlines = [UserProfileInlineAdmin]

The view you get from an inline admin is clearly distinct from the main form (in this case, that of User), though. You can try it out to see what I mean. It's not horrible, but it's still a noticeable break in the form. The reason I mentioned how to add a field to a form earlier, is that if you wanted, you can make it look all like one form with a little bit of clever misdirection.

class UserAdminForm(forms.ModelForm):
    class Meta:
        model = User

    is_developer = forms.BooleanField(default=False)

    def save(self, commit=True):
        user = super(UserAdminForm, self).save(commit=commit)
        if user.pk:
            profile = user.get_profile()
            profile.is_developer = self.cleaned_data.get('is_developer')
            profile.save()

That's a simplistic example, but the idea is that you add the field(s) manually to the form, and then use them to actually update the other object manually when the main object being edited is saved.

Special notes related to User

Now, since you're dealing with User here, there's a lot more sticky details. First, User already has a UserAdmin and its own forms -- yes plural, forms. If you want to add new functionality, you need to make sure you keep the existing Django functionality in the process.

from django.contrib.auth.admin import UserAdmin
form django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm, UserChangeForm

class CustomUserCreationForm(UserCreationForm):
    # do stuff

class CustomUserChangeForm(UserChangeForm):
    # do stuff

class CustomUserAdmin(UserAdmin):
    form = CustomUserChangeForm
    add_form = CustomUserCreationForm

admin.site.unregister(User)
admin.site.register(User, CustomUserAdmin)

Also, UserAdmin has its own set of fieldsets defined. The defaults are:

fieldsets = (
    (None, {'fields': ('username', 'password')}),
    (_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
    (_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser', 'user_permissions')}),
    (_('Important dates'), {'fields': ('last_login', 'date_joined')}),
    (_('Groups'), {'fields': ('groups',)}),
)
add_fieldsets = (
    (None, {
        'classes': ('wide',),
        'fields': ('username', 'password1', 'password2')}
    ),
)

If you want to add a field or fields, you'll need to redefine those two attributes with your fields added where you want them.

like image 79
Chris Pratt Avatar answered Sep 23 '22 00:09

Chris Pratt