简体   繁体   中英

Django Admin Inlines With OneToOne Field

Here in my model, you can see that I have a SpecializedProfile with a OneToOne relationship with a UserProfile, with a OneToOne relationship with the django user model.

I want to create an admin for the SpecializedProfile containing inlines for the UserProfile and the django User model, so that I can create a SpecializedProfile all at once, without needing to go to the UserProfile page and the User page.

Here is my model:

class UserProfile(models.Model):
    user_auth = models.OneToOneField(User, related_name="profile", primary_key=True)
    # more fields...


class SpecializedProfile(models.Model):
    profile = models.OneToOneField(UserProfile, related_name="specialized_profile", primary_key=True)
    # More fields...

and here is my attempt at creating the admin:

class UserInline(admin.TabularInline):
    model = User
    fk_name = 'profile__specialized_profile'

class ProfileInline(admin.TabularInline):
    model = UserProfile
    fk_name = 'specialized_profile'

class SpecializedProfileAdmin(admin.ModelAdmin):
    model = SpecializedProfile
    inlines = [
        UserInline, ProfileInline
    ]

admin.site.register(SpecializedProfile, SpecializedProfileAdmin)

The admin isn't working, and I am getting this error:

<class 'profiles.admin.ProfileInline'>: (admin.E202) 'profiles.UserProfile' has no field named 'trainer'.
<class 'profiles.admin.UserInline'>: (admin.E202) 'auth.User' has no ForeignKey to 'profiles.SpecializedProfile'.

It seems like django wants the inlines to be on the models where the OneToOne fields are defined, and won't accept reverse relationships. I'd rather not have to go restructuring my models to make this work... is there anything I can do to make the inlines work with my model as-is?

I fixed that error by making reverse side inline, not from Profile to User but from overridden User to Profile:

class ProfileInline(admin.StackedInline):
    model = Profile

class IspUserAdmin(UserAdmin):
    list_display = ('username', 'first_name', 'last_name', 'email', 'is_staff', 'is_superuser', 'is_active')
    list_filter = ('date_joined', 'last_login', 'is_staff', 'is_superuser', 'is_active',)
    inlines = (ProfileInline,)

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

Then I also tweaked Profile admin (removed Add action and changed some field links to custom ones).

There's a django module on github that will do this for you, without you having to reverse the relationships: django_reverse_admin .

Once installed, your admin would look like:

# admin.py
from django_reverse_admin import ReverseModelAdmin


class SpecializedProfileAdmin(ReverseModelAdmin):
    model = SpecializedProfile
    inline_reverse = ['profile']
    inline_type = 'tabular'  # could also be 'stacked'

admin.site.register(SpecializedProfile, SpecializedProfileAdmin)

Unfortunately, I don't think it can do nested inlines (Django can't either), so that would only solve part of your problem. I know you didn't want to change your database structure, but SpecializedProfile really seems more like a subclass of UserProfile. If you rewrote your model like so:

class SpecializedProfile(UserProfile):
    # More fields...

Then you could have the admin like this:

# admin.py
from django_reverse_admin import ReverseModelAdmin

class UserProfileAdmin(ReverseModelAdmin):
    model = UserProfile
    inline_reverse = ['user_auth']
    inline_type = 'tabular'


class SpecializedProfileAdmin(ReverseModelAdmin):
    model = SpecializedProfile
    inline_reverse = ['user_auth']
    inline_type = 'tabular'

admin.site.register(SpecializedProfile, SpecializedProfileAdmin) 
admin.site.register(UserProfile, UserProfileAdmin)

This way, you can view everything inline for both UserProfile and SpecializedProfile.

There is no way nested inlines (inline inside inline) in django.contrib.admin .

maybe this help you:

class UserInline(admin.TabularInline):
    model = User

class ProfileInline(admin.TabularInline):
    model = UserProfile
    inlines = [UserInline]

class SpecializedProfileAdmin(admin.ModelAdmin):
    model = SpecializedProfile
    inlines = [ProfileInline]

You'd also need to provide your own templates that would have nested iteration over both the top level inline and it's child inline.

Also take a look at this , maybe help you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM