@ron6500

Настройка админка Django: Как отобразить поля из одной модели на превью другой?

Привет
Занимаюсь настройкой отображения в админке и возник вопрос.
Есть две модели: встроенная джанговская User и моя собственная UserInfo. Связь один к одному. Как я могу передать поля first_name и last_name из модели User в list_display или в search_fields для модели UserInfo?
скириншот для наглядности. Хочу, чтобы вместо колонки user были колонки first name и last name: https://www.screencast.com/t/Edl2lM0QXzZ

Текущий класс выглядит так:
class UserInfoAdmin(admin.ModelAdmin):

    list_display = ["user", "email", "position"]
    list_display_links = ["user", "email", "position"]
    list_filter = ["user", "email", "position"]
    search_fields = ["user", "email", "position", "phone", "location"]

    class Meta:
        model = UserInfo
  • Вопрос задан
  • 1697 просмотров
Решения вопроса 1
sergey-gornostaev
@sergey-gornostaev Куратор тега Django
Седой и строгий
Правильнее и проще было бы сделать UserInfoAdmin инлайном для UserAdmin. Но можно добиться и использования полей связанной модели:

from six import with_metaclass
from django.contrib import admin
from django.db import models

def getter_for_related_field(name, admin_order_field=None, short_description=None):
    related_names = name.split('__')
    def getter(self, obj):
        for related_name in related_names:
            obj = getattr(obj, related_name)
        return obj
    getter.admin_order_field = admin_order_field or name
    getter.short_description = short_description or related_names[-1].title().replace('_',' ')
    return getter


class RelatedFieldAdminMetaclass(type(admin.ModelAdmin)):
    def __new__(cls, name, bases, attrs):
        new_class = super(RelatedFieldAdminMetaclass, cls).__new__(cls, name, bases, attrs)
        for field in new_class.list_display:
            if '__' in field:
                setattr(new_class, field, getter_for_related_field(field))
        return new_class


class RelatedFieldAdmin(with_metaclass(RelatedFieldAdminMetaclass, admin.ModelAdmin)):
    def get_queryset(self, request):
        qs = super(RelatedFieldAdmin, self).get_queryset(request)
        select_related = [field.rsplit('__',1)[0] for field in self.list_display if '__' in field]
        model = qs.model
        for field_name in self.list_display:
            try:
                field = model._meta.get_field(field_name)
            except models.FieldDoesNotExist:
                continue
            if isinstance(field.rel, models.ManyToOneRel):
                select_related.append(field_name)
        return qs.select_related(*select_related)


@admin.register(UserInfo)
class UserInfoAdmin(RelatedFieldAdmin):
    list_display = ['user', 'user__first_name', 'user__last_name', 'user__email', 'position']
    list_display_links = list_display
    list_filter = ['user__is_staff', 'position']
    search_fields = ['user__username', 'user__first_name', 'user__last_name', 'user__email', 'position', 'phone', 'location']
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы