python - django admin




如何將一個對象的Django管理頁面中的鏈接添加到相關對象的管理頁面? (5)

為了解決django-admin中缺少嵌套內聯的問題 ,我將特殊情況放入兩個模板中,以便在管理員更改頁面和兩個模型的內聯管理員之間創建鏈接。

我的問題是:如何創建一個鏈接,從管理員更改頁面或一個模型的內聯管理員到管理員更改頁面或相關模型的內聯管理員乾淨利落,模板中沒有討厭的黑客?

我想要一個通用的解決方案,我可以應用於任何模型的管理員更改頁面或內聯管理員。

我有一個模型, post (不是它的真實姓名),它既是blog管理頁面的內聯,也有自己的管理頁面。 它不能只是內聯的原因是它有外鍵的模型只有在用它編輯時才有意義,而且只有在用blog編輯時才有意義。

對於post admin頁面,我更改了“fieldset.html”的一部分:

{% if field.is_readonly %}
    <p>{{ field.contents }}</p>
{% else %}
    {{ field.field }}
{% endif %}

{% if field.is_readonly %}
    <p>{{ field.contents }}</p>
{% else %}
    {% ifequal field.field.name "blog" %}
        <p>{{ field.field.form.instance.blog_link|safe }}</p>
    {% else %}
        {{ field.field }}
    {% endifequal %}
{% endif %}

創建指向blog管理頁面的鏈接,其中blog_link是模型上的方法:

def blog_link(self):
      return '<a href="%s">%s</a>' % (reverse("admin:myblog_blog_change",  
                                        args=(self.blog.id,)), escape(self.blog))

我無法在field.field.form.instance之外的任何地方找到blog實例的id

post為內聯的blog管理頁面上,我修改了“stacked.html”的一部分:

<h3><b>{{ inline_admin_formset.opts.verbose_name|title }}:</b>&nbsp;
<span class="inline_label">{% if inline_admin_form.original %}
    {{ inline_admin_form.original }}
{% else %}#{{ forloop.counter }}{% endif %}</span>

<h3><b>{{ inline_admin_formset.opts.verbose_name|title }}:</b>&nbsp;
<span class="inline_label">{% if inline_admin_form.original %}
    {% ifequal inline_admin_formset.opts.verbose_name "post" %}
    <a href="/admin/myblog/post/{{ inline_admin_form.pk_field.field.value }}/">
            {{ inline_admin_form.original }}</a>
{% else %}{{ inline_admin_form.original }}{% endifequal %}
{% else %}#{{ forloop.counter }}{% endif %}</span>

創建一個到post管理頁面的鏈接,因為在這裡我能夠找到存儲在外鍵字段中的id

我確信有更好,更通用的方法來添加管理表單的鏈接而不重複自己; 它是什麼?


Django 1.8中的新功能: show_change_link用於內聯管理員

在內聯模型中將show_change_link設置為True (默認為False),以便內聯對象具有指向其更改表單的鏈接(它們可以具有自己的內聯)。

from django.contrib import admin

class PostInline(admin.StackedInline):
    model = Post
    show_change_link = True
    ...

class BlogAdmin(admin.ModelAdmin):
    inlines = [PostInline]
    ...

class ImageInline(admin.StackedInline):
    # Assume Image model has foreign key to Post
    model = Image
    show_change_link = True
    ...

class PostAdmin(admin.ModelAdmin):
    inlines = [ImageInline]
    ...

admin.site.register(Blog, BlogAdmin)
admin.site.register(Post, PostAdmin)

使用readonly_fields

class MyInline(admin.TabularInline):
    model = MyModel
    readonly_fields = ['link']

    def link(self, obj):
        url = reverse(...)
        return mark_safe("<a href='%s'>edit</a>" % url)

    # the following is necessary if 'link' method is also used in list_display
    link.allow_tags = True

我認為agf的解決方案非常棒 - 給他帶來很多榮譽。 但我需要更多功能:

  • 能夠為一個管理員提供多個鏈接
  • 能夠鏈接到不同的應用程序中的模型

解:

def add_link_field(target_model = None, field = '', app='', field_name='link',
                   link_text=unicode):
    def add_link(cls):
        reverse_name = target_model or cls.model.__name__.lower()
        def link(self, instance):
            app_name = app or instance._meta.app_label
            reverse_path = "admin:%s_%s_change" % (app_name, reverse_name)
            link_obj = getattr(instance, field, None) or instance
            url = reverse(reverse_path, args = (link_obj.id,))
            return mark_safe("<a href='%s'>%s</a>" % (url, link_text(link_obj)))
        link.allow_tags = True
        link.short_description = reverse_name + ' link'
        setattr(cls, field_name, link)
        cls.readonly_fields = list(getattr(cls, 'readonly_fields', [])) + \
            [field_name]
        return cls
    return add_link

用法:

# 'apple' is name of model to link to
# 'fruit_food' is field name in `instance`, so instance.fruit_food = Apple()
# 'link2' will be name of this field
@add_link_field('apple','fruit_food',field_name='link2')
# 'cheese' is name of model to link to
# 'milk_food' is field name in `instance`, so instance.milk_food = Cheese()
# 'milk' is the name of the app where Cheese lives
@add_link_field('cheese','milk_food', 'milk')
class FoodAdmin(admin.ModelAdmin):
    list_display = ("id", "...", 'link', 'link2')

我很抱歉這個例子太不合邏輯了,但我不想使用我的數據。


查看管理類的來源是有啟發性的:它表明在上下文中有一個對象可用於名為“original”的管理視圖。

這是類似的情況,我需要將一些信息添加到更改列表視圖中: 將數據添加到管理模板 (在我的博客上)。


這是我目前的解決方案,基於Pannu(在他的編輯中)和Mikhail的建議。

我有一些頂級管理員更改視圖,我需要鏈接到相關對象的頂級管理員更改視圖,以及一些內聯管理員更改視圖,我需要鏈接到頂級管理員更改視圖同一個對象。 因此,我想分析鏈接方法,而不是為每個管理員更改視圖重複它的變體。

我使用類裝飾器來創建可調用的link ,並將其添加到readonly_fields

def add_link_field(target_model = None, field = '', link_text = unicode):
    def add_link(cls):
        reverse_name = target_model or cls.model.__name__.lower()
        def link(self, instance):
            app_name = instance._meta.app_label
            reverse_path = "admin:%s_%s_change" % (app_name, reverse_name)
            link_obj = getattr(instance, field, None) or instance
            url = reverse(reverse_path, args = (link_obj.id,))
            return mark_safe("<a href='%s'>%s</a>" % (url, link_text(link_obj)))
        link.allow_tags = True
        link.short_description = reverse_name + ' link'
        cls.link = link
        cls.readonly_fields = list(getattr(cls, 'readonly_fields', [])) + ['link']
        return cls
    return add_link

如果您需要以某種方式獲取鏈接文本而不是僅僅在您要鏈接的對像上調用unicode ,則還可以傳遞自定義可調用對象。

我這樣使用它:

# the first 'blog' is the name of the model who's change page you want to link to
# the second is the name of the field on the model you're linking from
# so here, Post.blog is a foreign key to a Blog object. 
@add_link_field('blog', 'blog')
class PostAdmin(admin.ModelAdmin):
    inlines = [SubPostInline, DefinitionInline]
    fieldsets = ((None, {'fields': (('link', 'enabled'),)}),)
    list_display = ('__unicode__', 'enabled', 'link')

# can call without arguments when you want to link to the model change page
# for the model of an inline model admin.
@add_link_field()
class PostInline(admin.StackedInline):
    model = Post
    fieldsets = ((None, {'fields': (('link', 'enabled'),)}),)
    extra = 0

當然,如果我可以在Blog管理員更改頁面上的Post內聯管理員中嵌入SubPostDefinition的管理員更改視圖而不修補Django,那麼這一切都不是必需的。





django-templates