如何在fieldset中显示Django管理内联模型?

时间:2021-12-01 20:42:01

Consider the following ModelAdmin. In this instance, I'd like to have the inline "Book" UI display between the "None" fieldset and the Notes fieldset. Is that possible?

考虑以下ModelAdmin。在这个实例中,我希望在“None”字段集和Notes fieldset之间显示内联的“Book”UI。这有可能吗?

class AuthorAdmin(admin.ModelAdmin):
    inlines = [BookInline]

    fieldsets = (
            (None, {
                'fields': ('author_name', 'date_of_birth')
            }),
            ('Notes', {
                'fields': (['notes'])
            }),
    )

3 个解决方案

#1


6  

Unfortunately this is not possible with (the standard template from) django. If you look at the template for the change_form, you can see that inlines are always rendered separately after the fieldset: https://github.com/django/django/blob/master/django/contrib/admin/templates/admin/change_form.html

不幸的是,对于django来说,这是不可能的。如果您查看change_form的模板,您可以看到inlines总是在fieldset之后分别呈现:https://github.com/django/django/blob/master/django/后悔/管理/templates/admin/change_form.html

The only work-around I see is to write a custom template with respect to the order you want.

我所看到的惟一解决方法是针对您想要的顺序编写自定义模板。

#2


10  

Bertrand Bortage posted another solution here: https://groups.google.com/forum/#!topic/django-users/yUq2Nvx_4eM

伯特兰·博塔格在这里发布了另一个解决方案:https://groups.google.com/forum/#

A late reply to say that I just pushed a fairly clean solution to this problem in one of my projects: https://github.com/dezede/dezede/commit/ed13ccaf34494e71fd913fd785c229052f6acdc8.

我刚刚在我的一个项目中推出了一个相当干净的解决方案:https://github.com/dezede/dezedezede/commit/ed13ccaf34494e71fd913fd785c229052f6acdc8。

The idea is to define fieldsets_and_inlines_order in your ModelAdmin(s), an iterable of 'f' and 'i' characters (for "fieldset" and "inline") that specifies the order between the first fieldsets and inlines. If len(fieldsets_and_inlines_order) < len(fieldsets) + len(inlines), the remaining follows the original behaviour (fieldsets first, then all inlines).

其思想是在您的ModelAdmin中定义fieldsets_and_inlines_order,一个可迭代的'f'和'i'字符(用于"fieldset"和"inline"),它指定了第一个fieldset和inline之间的顺序。如果len(fieldsets_and_inlines_order) < len(fieldset) + len(inlines),其余的则遵循原始行为(首先是fieldset,然后是所有的inlines)。

Example: you have 5 fieldsets and 3 inlines, defining fieldsets_and_inlines_order = ('f', 'f', 'i', 'f', 'i') will give you: fieldset fieldset inline fieldset inline fieldset fieldset inline Hope it helps, Bertrand

示例:您有5个fieldset和3个inline,定义fieldsets_and_inlines_order = ('f', 'f', 'i', 'f', 'i')将提供给您:fieldset字段集内联的fieldset字段集,内联的希望它有帮助,Bertrand。

I had another idea which is worth considering. Create a readonly placeholder field in your fieldsets for each inline then use jQuery to move the inlines into place for each placeholder. Something like this (jQuery omitted as I haven't written it yet):

我有另一个值得考虑的想法。在字段集中为每个内联创建一个readonly占位符字段,然后使用jQuery为每个占位符将inlines移动到相应的位置。类似这样的东西(jQuery省略了,因为我还没写):

fieldsets = (
        (None, {
            'fields': (
                ('inline_images',)
                ('thumbnail_image',),
                ('inline_authors',)
                ('title', 'is_active', 'order',)
            ),
        }),
    )

readonly_fields = ('inline_images', 'inline_authors')

inline_images = '<span id='replaceme inline_images'></span>'
inline_images.allow_tags = True
inline_authors = '<span id='replaceme inline_authors'></span>'
inline_authors.allow_tags = True

One more thing - there is an open Django issue asking for this positioning of inlines: https://code.djangoproject.com/ticket/4848

还有一件事——有一个开放的Django问题需要对inline进行这样的定位:https://code.djangoproject.com/ticket/4848

#3


0  

I have constructed another quite generic solution...

我构建了另一个非常通用的解决方案……

In your admin.py add a new field to your Inline:

在你的管理。py为您的内联添加了一个新字段:

class YourModelInline(admin.TabularInline):
    model = YourModel
    after_field = "fieldname_of_field_before_inline"

Then customize render_change_form of AdminClass of the model that holds the Inline:

然后定制包含内联的模型的AdminClass的render_change_form:

class EditModelAdmin(model.ModelAdmin):
    inlines = [YourModelInline,]

    def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
        sorted_inline_formsets = {}
        inline_admin_formsets = context['inline_admin_formsets']
        formsets_to_remove = []

        for inline_formset in inline_admin_formsets:
            if hasattr(inline_formset.opts, 'after_field'):
                fieldname = inline_formset.opts.after_field
                if fieldname in sorted_inline_formsets:
                    sorted_inline_formsets[fieldname].append(inline_formset)
                else:
                    sorted_inline_formsets.update({
                        fieldname: [inline_formset,]
                    })
                formsets_to_remove.append(inline_formset)
        for inline_formset in formsets_to_remove:
            inline_admin_formsets.remove(inline_formset)

        context.update({
            'sorted_inline_formsets': sorted_inline_formsets,
            'inline_admin_formsets': inline_admin_formsets
        })
        return super(EditModelAdmin, self).render_change_form(request, context, add=add,
                                                       change=change, obj=obj, form_url=form_url)

We are moving all Inlines with extra field into own dictionary with fieldname as key... For it to be rendered correctly create file /templates/admin/includes/fieldset.html that overrides standard django fieldset.html with following content:

我们正在将所有的Inlines添加到自己的字典中,并将fieldname作为键。为了正确地呈现它,创建文件/模板/admin/include /fieldset。重写标准django字段集的html。html与以下内容:

{% load custom_filter %}
<fieldset class="module aligned {{ fieldset.classes }}">
        {% if fieldset.name %}<h2>{{ fieldset.name }}</h2>{% endif %}
        {% if fieldset.description %}
            <div class="description">{{ fieldset.description|safe }}</div>
        {% endif %}
        {% for line in fieldset %}
            <div class="form-row{% if line.fields|length_is:'1' and line.errors %} errors{% endif %}{% if not line.has_visible_field %} hidden{% endif %}{% for field in line %}{% if field.field.name %} field-{{ field.field.name }}{% endif %}{% endfor %}">
                {% if line.fields|length_is:'1' %}{{ line.errors }}{% endif %}
                {% for field in line %}
                    <div{% if not line.fields|length_is:'1' %} class="field-box{% if field.field.name %} field-{{ field.field.name }}{% endif %}{% if not field.is_readonly and field.errors %} errors{% endif %}{% if field.field.is_hidden %} hidden{% endif %}"{% elif field.is_checkbox %} class="checkbox-row"{% endif %}>
                        {% if not line.fields|length_is:'1' and not field.is_readonly %}{{ field.errors }}{% endif %}
                        {% if field.is_checkbox %}
                            {{ field.field }}{{ field.label_tag }}
                        {% else %}
                            {{ field.label_tag }}
                            {% if field.is_readonly %}
                                <div class="readonly">{{ field.contents }}</div>
                            {% else %}
                                {{ field.field }}
                            {% endif %}
                        {% endif %}
                        {% if field.field.help_text %}
                            <div class="help">{{ field.field.help_text|safe }}</div>
                        {% endif %}
                    </div>
                    {% if field.field.name %}
                        {% with field.field.name as fieldname %}
                            {% if sorted_inline_formsets|get_dict_value:fieldname != False %}
                                {% for inline_admin_formset in sorted_inline_formsets|get_dict_value:fieldname %}
                                    {% include inline_admin_formset.opts.template %}
                                {% endfor %}
                            {% endif %}
                        {% endwith %}
                    {% endif %}
                {% endfor %}
            </div>
        {% endfor %}
    </fieldset>

This will add sorted inlines after the corresponding field... Now you only need the custom_filter for working with the dictionary in django template, create templatetags/custom_filter.py and add:

这将在相应的字段之后添加已排序的inline…现在,您只需要custom_filter就可以在django模板中使用字典,创建templatetags/custom_filter。py和添加:

@register.filter
def get_dict_value(dict, key):
    if key in dict:
        return dict[key]
    else:
        return False

And voila: You can enter any fieldname into any Inline to add it after that field... It is a bit work to setup but if you have several inlines to sort it might be a cleaner way...

你可以在任何内联中输入任何字段名,然后添加它……安装起来有点麻烦,但是如果你有几个内线来排序,那可能是一种更干净的方式……

#1


6  

Unfortunately this is not possible with (the standard template from) django. If you look at the template for the change_form, you can see that inlines are always rendered separately after the fieldset: https://github.com/django/django/blob/master/django/contrib/admin/templates/admin/change_form.html

不幸的是,对于django来说,这是不可能的。如果您查看change_form的模板,您可以看到inlines总是在fieldset之后分别呈现:https://github.com/django/django/blob/master/django/后悔/管理/templates/admin/change_form.html

The only work-around I see is to write a custom template with respect to the order you want.

我所看到的惟一解决方法是针对您想要的顺序编写自定义模板。

#2


10  

Bertrand Bortage posted another solution here: https://groups.google.com/forum/#!topic/django-users/yUq2Nvx_4eM

伯特兰·博塔格在这里发布了另一个解决方案:https://groups.google.com/forum/#

A late reply to say that I just pushed a fairly clean solution to this problem in one of my projects: https://github.com/dezede/dezede/commit/ed13ccaf34494e71fd913fd785c229052f6acdc8.

我刚刚在我的一个项目中推出了一个相当干净的解决方案:https://github.com/dezede/dezedezede/commit/ed13ccaf34494e71fd913fd785c229052f6acdc8。

The idea is to define fieldsets_and_inlines_order in your ModelAdmin(s), an iterable of 'f' and 'i' characters (for "fieldset" and "inline") that specifies the order between the first fieldsets and inlines. If len(fieldsets_and_inlines_order) < len(fieldsets) + len(inlines), the remaining follows the original behaviour (fieldsets first, then all inlines).

其思想是在您的ModelAdmin中定义fieldsets_and_inlines_order,一个可迭代的'f'和'i'字符(用于"fieldset"和"inline"),它指定了第一个fieldset和inline之间的顺序。如果len(fieldsets_and_inlines_order) < len(fieldset) + len(inlines),其余的则遵循原始行为(首先是fieldset,然后是所有的inlines)。

Example: you have 5 fieldsets and 3 inlines, defining fieldsets_and_inlines_order = ('f', 'f', 'i', 'f', 'i') will give you: fieldset fieldset inline fieldset inline fieldset fieldset inline Hope it helps, Bertrand

示例:您有5个fieldset和3个inline,定义fieldsets_and_inlines_order = ('f', 'f', 'i', 'f', 'i')将提供给您:fieldset字段集内联的fieldset字段集,内联的希望它有帮助,Bertrand。

I had another idea which is worth considering. Create a readonly placeholder field in your fieldsets for each inline then use jQuery to move the inlines into place for each placeholder. Something like this (jQuery omitted as I haven't written it yet):

我有另一个值得考虑的想法。在字段集中为每个内联创建一个readonly占位符字段,然后使用jQuery为每个占位符将inlines移动到相应的位置。类似这样的东西(jQuery省略了,因为我还没写):

fieldsets = (
        (None, {
            'fields': (
                ('inline_images',)
                ('thumbnail_image',),
                ('inline_authors',)
                ('title', 'is_active', 'order',)
            ),
        }),
    )

readonly_fields = ('inline_images', 'inline_authors')

inline_images = '<span id='replaceme inline_images'></span>'
inline_images.allow_tags = True
inline_authors = '<span id='replaceme inline_authors'></span>'
inline_authors.allow_tags = True

One more thing - there is an open Django issue asking for this positioning of inlines: https://code.djangoproject.com/ticket/4848

还有一件事——有一个开放的Django问题需要对inline进行这样的定位:https://code.djangoproject.com/ticket/4848

#3


0  

I have constructed another quite generic solution...

我构建了另一个非常通用的解决方案……

In your admin.py add a new field to your Inline:

在你的管理。py为您的内联添加了一个新字段:

class YourModelInline(admin.TabularInline):
    model = YourModel
    after_field = "fieldname_of_field_before_inline"

Then customize render_change_form of AdminClass of the model that holds the Inline:

然后定制包含内联的模型的AdminClass的render_change_form:

class EditModelAdmin(model.ModelAdmin):
    inlines = [YourModelInline,]

    def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
        sorted_inline_formsets = {}
        inline_admin_formsets = context['inline_admin_formsets']
        formsets_to_remove = []

        for inline_formset in inline_admin_formsets:
            if hasattr(inline_formset.opts, 'after_field'):
                fieldname = inline_formset.opts.after_field
                if fieldname in sorted_inline_formsets:
                    sorted_inline_formsets[fieldname].append(inline_formset)
                else:
                    sorted_inline_formsets.update({
                        fieldname: [inline_formset,]
                    })
                formsets_to_remove.append(inline_formset)
        for inline_formset in formsets_to_remove:
            inline_admin_formsets.remove(inline_formset)

        context.update({
            'sorted_inline_formsets': sorted_inline_formsets,
            'inline_admin_formsets': inline_admin_formsets
        })
        return super(EditModelAdmin, self).render_change_form(request, context, add=add,
                                                       change=change, obj=obj, form_url=form_url)

We are moving all Inlines with extra field into own dictionary with fieldname as key... For it to be rendered correctly create file /templates/admin/includes/fieldset.html that overrides standard django fieldset.html with following content:

我们正在将所有的Inlines添加到自己的字典中,并将fieldname作为键。为了正确地呈现它,创建文件/模板/admin/include /fieldset。重写标准django字段集的html。html与以下内容:

{% load custom_filter %}
<fieldset class="module aligned {{ fieldset.classes }}">
        {% if fieldset.name %}<h2>{{ fieldset.name }}</h2>{% endif %}
        {% if fieldset.description %}
            <div class="description">{{ fieldset.description|safe }}</div>
        {% endif %}
        {% for line in fieldset %}
            <div class="form-row{% if line.fields|length_is:'1' and line.errors %} errors{% endif %}{% if not line.has_visible_field %} hidden{% endif %}{% for field in line %}{% if field.field.name %} field-{{ field.field.name }}{% endif %}{% endfor %}">
                {% if line.fields|length_is:'1' %}{{ line.errors }}{% endif %}
                {% for field in line %}
                    <div{% if not line.fields|length_is:'1' %} class="field-box{% if field.field.name %} field-{{ field.field.name }}{% endif %}{% if not field.is_readonly and field.errors %} errors{% endif %}{% if field.field.is_hidden %} hidden{% endif %}"{% elif field.is_checkbox %} class="checkbox-row"{% endif %}>
                        {% if not line.fields|length_is:'1' and not field.is_readonly %}{{ field.errors }}{% endif %}
                        {% if field.is_checkbox %}
                            {{ field.field }}{{ field.label_tag }}
                        {% else %}
                            {{ field.label_tag }}
                            {% if field.is_readonly %}
                                <div class="readonly">{{ field.contents }}</div>
                            {% else %}
                                {{ field.field }}
                            {% endif %}
                        {% endif %}
                        {% if field.field.help_text %}
                            <div class="help">{{ field.field.help_text|safe }}</div>
                        {% endif %}
                    </div>
                    {% if field.field.name %}
                        {% with field.field.name as fieldname %}
                            {% if sorted_inline_formsets|get_dict_value:fieldname != False %}
                                {% for inline_admin_formset in sorted_inline_formsets|get_dict_value:fieldname %}
                                    {% include inline_admin_formset.opts.template %}
                                {% endfor %}
                            {% endif %}
                        {% endwith %}
                    {% endif %}
                {% endfor %}
            </div>
        {% endfor %}
    </fieldset>

This will add sorted inlines after the corresponding field... Now you only need the custom_filter for working with the dictionary in django template, create templatetags/custom_filter.py and add:

这将在相应的字段之后添加已排序的inline…现在,您只需要custom_filter就可以在django模板中使用字典,创建templatetags/custom_filter。py和添加:

@register.filter
def get_dict_value(dict, key):
    if key in dict:
        return dict[key]
    else:
        return False

And voila: You can enter any fieldname into any Inline to add it after that field... It is a bit work to setup but if you have several inlines to sort it might be a cleaner way...

你可以在任何内联中输入任何字段名,然后添加它……安装起来有点麻烦,但是如果你有几个内线来排序,那可能是一种更干净的方式……