Django Admin中带有一对一字段的内联

2 投票
2 回答
5324 浏览
提问于 2025-04-30 23:15

在我的模型中,你可以看到我有一个叫做SpecializedProfile的部分,它和UserProfile之间是一对一的关系,而UserProfile又和django的用户模型之间也是一对一的关系。

我想为SpecializedProfile创建一个管理界面,这个界面里包含UserProfile和django用户模型的内联,这样我就可以一次性创建一个SpecializedProfile,而不需要分别去UserProfile页面和用户页面。

这是我的模型:

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

这是我尝试创建管理界面的代码:

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)

但是这个管理界面没有正常工作,我遇到了这个错误:

<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'.

看起来django希望内联出现在定义了一对一字段的模型上,而不接受反向关系。我不想为了让它工作而重新调整我的模型结构……有没有什么办法可以让内联在我的模型上正常工作呢?

暂无标签

2 个回答

0

在GitHub上有一个django模块,可以帮你解决这个问题,你不需要自己去反向处理关系:django_reverse_admin

安装后,你的管理界面会变成这样:

# 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)

不过,很遗憾,我觉得它不能处理嵌套的内联(Django本身也不能),所以这只能解决你问题的一部分。我知道你不想改变数据库结构,但SpecializedProfile看起来更像是UserProfile的一个子类。如果你把模型改成这样:

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

那么你的管理界面就可以变成这样:

# 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)

这样一来,你就可以同时查看UserProfile和SpecializedProfile的所有信息了。

2

我通过把反向关系设置为内联来解决那个错误,不是从个人资料(Profile)到用户(User),而是从重写的用户(User)到个人资料(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)

然后我还调整了个人资料管理(Profile admin),去掉了添加操作,并把一些字段链接改成了自定义的。

撰写回答