Непрямой встроенный в Django admin
У меня есть следующие модели:
class UserProfile(models.Model):
user = models.OneToOneField(User)
class Property(models.Model):
user = models.ForeignKey(User)
Я хотел бы создать TabularInline
, отображающий каждое Свойство, связанное с конкретным UserProfile
на его странице администратора Django. Проблема здесь, конечно, в том, что свойство не имеет ForeignKey
непосредственно к UserProfile
, поэтому я не могу просто написать
class PropertyTabularInline(admin.TabularInline):
model = Property
class UserProfileAdmin(admin.ModelAdmin):
inlines = (PropertyTabularInline,)
Как я могу легко делать то, что хочу?
Ответы
Ответ 1
Вы можете перезаписать страницу администрирования пользователя, чтобы отобразить модели Profile
и Property
.
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from myapp.models import *
class ProfileInline(admin.TabularInline):
model = Profile
class PropertyInline(admin.TabularInline):
model = Property
class UserAdmin(UserAdmin):
inlines = (ProfileInline, PropertyInline,)
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
Вы также можете удалить любые нежелательные/неиспользуемые свойства пользователя (например, группы или разрешения)
здесь: https://docs.djangoproject.com/en/1.8/topics/auth/customizing/#extending-the-existing-user-model
и здесь:
https://docs.djangoproject.com/en/1.8/topics/auth/customizing/#a-full-example
Ответ 2
class PropertyTabularInline(admin.TabularInline):
model = Property
def formfield_for_dbfield(self, field, **kwargs):
if field.name == 'user':
# implement your method to get userprofile object from request here.
user_profile = self.get_object(kwargs['request'], UserProfile)
kwargs["queryset"] = Property.objects.filter(user=user_profile)
return super(PropertyInLine, self).formfield_for_dbfield(field, **kwargs)
как только это будет сделано, вы можете добавить этот встроенный пользователь UserProfileAdmin, например:
class UserProfileAdmin(admin.ModelAdmin):
inlines = (PropertyTabularInline,)
Не тестировали, но это должно работать.
Ответ 3
Это можно сделать, сделав одно изменение в ваших моделях.
Вместо создания отношения OneToOne от UserProfile
до User
, подкласса User
, создающего UserProfile
. Код должен выглядеть так:
class UserProfile(User):
# some other fields, no relation to User model
class Property(models.Model):
user = models.ForeignKey(User)
Это приведет к созданию модели UserProfile
, у которой скрытое отношение OneToOne к модели User
, оно не будет дублировать модель пользователя.
После выполнения этого изменения ваш код будет работать. Есть некоторые изменения под капотом, например, UserProfile
больше не имеет собственного идентификатора, вы можете получить доступ к полям из User
внутри UserProfile
и трудно переопределить модель User
, используя settings.AUTH_USER_MODEL
(для этого потребуется создать некоторые пользовательская функция возвращает правильный тип и меняет миграцию вручную), но если это не проблема для вас, это может быть хорошим решением.