هل يمكن لـ "list_display" في سمات عرض Django ModelAdmin لحقول ForeignKey؟
-
03-07-2019 - |
سؤال
انا املك Person
النموذج الذي له علاقة مفتاح خارجي Book
, ، الذي يحتوي على عدد من الحقول ، لكنني أكثر قلقًا بشأنه author
(تشارفيلد قياسي).
مع ما يقال ، في بلدي PersonAdmin
النموذج ، أود عرضه book.author
استخدام list_display
:
class PersonAdmin(admin.ModelAdmin):
list_display = ['book.author',]
لقد جربت كل الأساليب الواضحة للقيام بذلك ، لكن لا شيء يبدو أنه يعمل.
أي اقتراحات؟
المحلول
كخيار آخر ، يمكنك البحث مثل:
class UserAdmin(admin.ModelAdmin):
list_display = (..., 'get_author')
def get_author(self, obj):
return obj.book.author
get_author.short_description = 'Author'
get_author.admin_order_field = 'book__author'
نصائح أخرى
على الرغم من كل الإجابات الرائعة أعلاه وبسبب كونني جديدًا على Django ، كنت لا أزال عالقًا. إليكم توضيحي من منظور مبتدئ للغاية.
النماذج
class Author(models.Model):
name = models.CharField(max_length=255)
class Book(models.Model):
author = models.ForeignKey(Author)
title = models.CharField(max_length=255)
admin.py (طريقة غير صحيحة) - تعتقد أنه سيعمل باستخدام "model__field" للإشارة ، لكنه لا يفعل ذلك
class BookAdmin(admin.ModelAdmin):
model = Book
list_display = ['title', 'author__name', ]
admin.site.register(Book, BookAdmin)
admin.py (الطريقة الصحيحة) - هذه هي الطريقة التي تشير بها إلى اسم مفتاح خارجي طريقة Django
class BookAdmin(admin.ModelAdmin):
model = Book
list_display = ['title', 'get_name', ]
def get_name(self, obj):
return obj.author.name
get_name.admin_order_field = 'author' #Allows column order sorting
get_name.short_description = 'Author Name' #Renames column head
#Filtering on side - for some reason, this works
#list_filter = ['title', 'author__name']
admin.site.register(Book, BookAdmin)
للحصول على مرجع إضافي ، راجع رابط نموذج Django هنا
مثل الباقي ، ذهبت مع Callables أيضا. لكن لديهم جانبًا سلبيًا واحد: افتراضيًا ، لا يمكنك طلبهم. لحسن الحظ ، هناك حل لذلك:
def author(self):
return self.book.author
author.admin_order_field = 'book__author'
يرجى ملاحظة أن إضافة get_author
ستؤدي الوظيفة إلى إبطاء list_display في المسؤول ، لأن إظهار كل شخص سيجعل استعلام SQL.
لتجنب ذلك ، تحتاج إلى تعديل get_queryset
الطريقة في personadmin ، على سبيل المثال:
def get_queryset(self, request):
return super(PersonAdmin,self).get_queryset(request).select_related('book')
قبل: 73 استعلامات في 36.02 مللي ثانية (67 استفسارات مكررة في المشرف)
بعد: 6 استفسارات في 10.81ms
وفقًا للوثائق ، يمكنك فقط عرض __unicode__
تمثيل أجنبي:
http://docs.djangoproject.com/en/dev/ref/contrib/admin/#list-display
يبدو من الغريب أنه لا يدعم 'book__author'
تنسيق النمط الذي يتم استخدامه في كل مكان آخر في واجهة برمجة تطبيقات DB.
اتضح أن هناك تذكرة لهذه الميزة, ، والتي تم تمييزها كما لا إصلاح.
يمكنك إظهار ما تريد في عرض القائمة باستخدام قابلة للاتصال. انها تبدو مثل هذا:
def book_author(object): return object.book.author class PersonAdmin(admin.ModelAdmin): list_display = [book_author,]
لقد نشرت للتو مقتطفًا يجعل Admin.ModelAdmin دعم "__" بناء جملة:
http://djangosnippets.org/snippets/2887/
لذلك يمكنك أن تفعل:
class PersonAdmin(RelatedFieldAdmin):
list_display = ['book__author',]
هذا هو مجرد القيام بنفس الشيء الموضح في الإجابات الأخرى ، لكنه يعتني تلقائيًا (1) تعيين admin_order_field (2) تعيين Short_description و (3) تعديل QuerySet لتجنب ضرب قاعدة البيانات لكل صف.
This one's already accepted, but if there are any other dummies out there (like me) that didn't immediately get it from the presently accepted answer, here's a bit more detail.
The model class referenced by the ForeignKey
needs to have a __unicode__
method within it, like here:
class Category(models.Model):
name = models.CharField(max_length=50)
def __unicode__(self):
return self.name
That made the difference for me, and should apply to the above scenario. This works on Django 1.0.2.
إذا جربته في الخط ، فلن تنجح إلا إذا:
في خطتك:
class AddInline(admin.TabularInline):
readonly_fields = ['localname',]
model = MyModel
fields = ('localname',)
في النموذج الخاص بك (MyModel):
class MyModel(models.Model):
localization = models.ForeignKey(Localizations)
def localname(self):
return self.localization.name
إذا كان لديك الكثير من حقول سمات العلاقة لاستخدامها في list_display
ولا تريد إنشاء وظيفة (وسماتها) لكل واحدة ، وسيتم تجاوز الحل الأوساخ ولكن البسيط ModelAdmin
stace __getattr__
الطريقة ، إنشاء callables على الذبابة:
class DynamicLookupMixin(object):
'''
a mixin to add dynamic callable attributes like 'book__author' which
return a function that return the instance.book.author value
'''
def __getattr__(self, attr):
if ('__' in attr
and not attr.startswith('_')
and not attr.endswith('_boolean')
and not attr.endswith('_short_description')):
def dyn_lookup(instance):
# traverse all __ lookups
return reduce(lambda parent, child: getattr(parent, child),
attr.split('__'),
instance)
# get admin_order_field, boolean and short_description
dyn_lookup.admin_order_field = attr
dyn_lookup.boolean = getattr(self, '{}_boolean'.format(attr), False)
dyn_lookup.short_description = getattr(
self, '{}_short_description'.format(attr),
attr.replace('_', ' ').capitalize())
return dyn_lookup
# not dynamic lookup, default behaviour
return self.__getattribute__(attr)
# use examples
@admin.register(models.Person)
class PersonAdmin(admin.ModelAdmin, DynamicLookupMixin):
list_display = ['book__author', 'book__publisher__name',
'book__publisher__country']
# custom short description
book__publisher__country_short_description = 'Publisher Country'
@admin.register(models.Product)
class ProductAdmin(admin.ModelAdmin, DynamicLookupMixin):
list_display = ('name', 'category__is_new')
# to show as boolean field
category__is_new_boolean = True
كما جوهر هنا
سمات خاصة قابلة للاتصال مثل boolean
و short_description
يجب تعريفها على أنها ModelAdmin
سمات ، على سبيل المثال book__author_verbose_name = 'Author name'
و category__is_new_boolean = True
.
القابلة للاستدعاء admin_order_field
يتم تعريف السمة تلقائيا.
لا تنس استخدام list_select_reled ميزة في الخاص بك ModelAdmin
لجعل Django تجنب الاستفسارات الدهنية.
هناك حزمة سهلة الاستخدام متوفرة في PYPI تعالج بالضبط: إدارة Django. يمكنك أيضا انظر الرمز في جيثب.
باستخدام هذا ، ما تريد تحقيقه بسيط مثل:
class PersonAdmin(RelatedFieldAdmin):
list_display = ['book__author',]
يحتوي كلا الرابطين على تفاصيل كاملة للتثبيت والاستخدام ، لذا لن ألصقهما هنا في حالة تغييرها.
مثل ملاحظة جانبية ، إذا كنت تستخدم بالفعل شيء آخر غير model.Admin
(على سبيل المثال كنت أستخدم SimpleHistoryAdmin
بدلاً من ذلك) ، يمكنك القيام بذلك: class MyAdmin(SimpleHistoryAdmin, RelatedFieldAdmin)
.
عملت إجابة Alexrobbins بالنسبة لي ، إلا أن الخطين الأولين يجب أن يكونوا في النموذج (ربما تم افتراض ذلك؟) ، ويجب أن يشير إلى الذات:
def book_author(self):
return self.book.author
ثم يعمل جزء المسؤول بشكل جيد.
أنا أفضل هذا:
class CoolAdmin(admin.ModelAdmin):
list_display = ('pk', 'submodel__field')
@staticmethod
def submodel__field(obj):
return obj.submodel.field