Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I've overridden the UserAdmin class and wanted to add a user profile and some related objects as inline.

Userprofile works as expected, but for the ManyToMany relations I get now a table with related objects. That's not really ideal for my application, it's a bit cumbersome to change the related objects, and there's no need to add new objects this way.

I'd like to have a simple MultipleChoiceField containing the related objects. Is there an easy way to achieve this?

Here's my userprofile/admin.py:

from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin
from django.utils.translation import gettext_lazy as _
from django_admin_listfilter_dropdown.filters import RelatedOnlyDropdownFilter

from driverslog.models import Branch
from driverslog.models import Car
from .models import Userprofile

User = get_user_model()


class ProfileInline(admin.TabularInline):
    model = Userprofile
    can_delete = False
    max_num = 0
    extra = 0
    fk_name = 'user'


class CarInline(admin.TabularInline):
    model = Car.users.through
    can_delete = True
    verbose_name = _('Car')
    verbose_name_plural = _('Cars')
    extra = 0


class BranchInline(admin.TabularInline):
    model = Branch.users.through
    can_delete = True
    verbose_name = _('Branch')
    verbose_name_plural = _('Branches')
    extra = 0


class CustomUserAdmin(UserAdmin):
    inlines = (ProfileInline, BranchInline, CarInline)
    list_display = ('username', 'first_name', 'last_name', 'is_staff', 'is_superuser', 'represents')
    list_filter = ('is_active', 'is_staff', 'is_superuser', ('groups', RelatedOnlyDropdownFilter),
                   ('branches', RelatedOnlyDropdownFilter), ('profile__represent', RelatedOnlyDropdownFilter),
                   ('car', RelatedOnlyDropdownFilter))

    def represents(self, obj):
        return obj.profile.represent.count()

    represents.short_description = _('Represents')

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
230 views
Welcome To Ask or Share your Answers For Others

1 Answer

I solved it now without using inline fields.

What I did is overriding UserChangeForm and adding the fields for the reverse relation. It's working as expected and by now I didn't find any drawbacks (until now...).

admin.py:

class CustomUserAdmin(UserAdmin):
    inlines = (ProfileInline,)
    form = UserForm
    ...
    fieldsets = (
        (_('Personal info'), {'fields': ('username', 'first_name', 'last_name', 'email')}),
        (_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions')}),
        (_('Assignments'), {'fields': ('branches', 'cars')}),
    )

forms.py:

class UserForm(UserChangeForm):
    branches = forms.ModelMultipleChoiceField(queryset=Branch.objects.all())
    cars = forms.ModelMultipleChoiceField(queryset=Car.objects.all())

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        instance = kwargs.get('instance')
        if instance:
            self.fields["branches"].initial = instance.branches.all().values_list('id', flat=True)
            self.fields["cars"].initial = instance.cars.all().values_list('id', flat=True)

    def save(self, commit=True):
        if self.is_valid():
            self.instance.cars.set(self.cleaned_data.get('cars'))
            self.instance.branches.set(self.cleaned_data.get('branches'))
        return super().save(commit)

models.py:

class Userprofile(models.Model):
    class Meta:
        verbose_name = _('Profile')
        verbose_name_plural = _('Profiles')
    user = models.OneToOneField(get_user_model(), on_delete=models.CASCADE, unique=True, related_name='profile', verbose_name=_('User'))
    represent = models.ManyToManyField(get_user_model(), related_name='represent', blank=True, verbose_name=_('Represents'))

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...