web-dev-qa-db-ja.com

admin.ModelAdminオブジェクトの注文

トッピングクラスとピザクラスを備えたピザアプリケーションがあり、それらがDjango管理者のように表示されているとします:

PizzaApp
-
Toppings      >>>>>>>>>>      Add / Change

Pizzas        >>>>>>>>>>      Add / Change

しかし、私はそれらをこのようにしたいと思います:

PizzaApp
-
Pizzas        >>>>>>>>>>      Add / Change

Toppings      >>>>>>>>>>      Add / Change

Admin.pyでそれを構成するにはどうすればよいですか?

34
Rui Ferreira

これは実際には Djangoチュートリアル のパート2)の一番下で説明されています。

関連するセクションは次のとおりです。

管理者インデックスページをカスタマイズします

同様に、Django管理者インデックスページのルックアンドフィールをカスタマイズすることもできます。

デフォルトでは、管理アプリケーションに登録されているINSTALLED_APPS内のすべてのアプリがアルファベット順に表示されます。レイアウトに大幅な変更を加えることができます。結局のところ、インデックスはおそらく管理者の最も重要なページであり、使いやすいはずです。

カスタマイズするテンプレートはadmin/index.htmlです。 (前のセクションのadmin/base_site.htmlと同じように、デフォルトのディレクトリからカスタムテンプレートディレクトリにコピーします。)ファイルを編集すると、app_listというテンプレート変数が使用されていることがわかります。この変数には、インストールされているすべてのDjangoアプリが含まれています。これを使用する代わりに、オブジェクト固有の管理ページへのリンクを最適な方法でハードコーディングできます。

10
Dave Kasper

試すことができる回避策は、models.pyを次のように微調整することです。

class Topping(models.Model):
    .
    .
    .
    class Meta:
        verbose_name_plural = "2. Toppings"

class Pizza(models.Model):
    .
    .
    .
    class Meta:
        verbose_name_plural = "1. Pizzas"

Djangoのベストプラクティスに反しているかどうかはわかりませんが、機能します(Djangoトランクでテスト済み)。

幸運を!

PS:この回答の投稿が遅すぎた場合は申し訳ありませんが、将来の同様の状況で他の人を助けることができます。

34
Roberto

これを10秒で解決したい場合は、verbose_name_pluralのスペースを使用してください。例:

class Topping(models.Model):
    class Meta:
        verbose_name_plural = "  Toppings" # 2 spaces

class Pizza(models.Model):
    class Meta:
        verbose_name_plural = " Pizzas" # 1 space

もちろん、それはエレガントではありませんが、より良い解決策が得られるまでしばらくは機能する可能性があります。

20
ptronico

私は最終的にこれのおかげでそれを行うことができました Djangoスニペット 、あなたはADMIN_REORDER設定に注意する必要があります:

ADMIN_REORDER = (
    ('app1', ('App1Model1', 'App1Model2', 'App1Model3')),
    ('app2', ('App2Model1', 'App2Model2')),
)

app1の前にプロジェクト名を付けることはできません。つまり、app1の代わりにmysite.app1を使用してください。

19
Emmanuel

そのための素敵なDjangoパッケージがあります:

https://pypi.python.org/pypi/Django-modeladmin-reorder

15
Jdruiter

これがEmmanuelが使用したスニペットで、Django 1.8:

Templatetags/admin_reorder.py:

from Django import template
from Django.conf import settings
from collections import OrderedDict

register = template.Library()

# from http://www.djangosnippets.org/snippets/1937/
def register_render_tag(renderer):
    """
    Decorator that creates a template tag using the given renderer as the 
    render function for the template tag node - the render function takes two 
    arguments - the template context and the tag token
    """
    def tag(parser, token):
        class TagNode(template.Node):
            def render(self, context):
                return renderer(context, token)
        return TagNode()
    for copy_attr in ("__dict__", "__doc__", "__name__"):
        setattr(tag, copy_attr, getattr(renderer, copy_attr))
    return register.tag(tag)

@register_render_tag
def admin_reorder(context, token):
    """
    Called in admin/base_site.html template override and applies custom ordering
    of apps/models defined by settings.ADMIN_REORDER
    """
    # sort key function - use index of item in order if exists, otherwise item
    sort = lambda order, item: (order.index(item), "") if item in order else (
        len(order), item)
    if "app_list" in context:
        # sort the app list
        order = OrderedDict(settings.ADMIN_REORDER)
        context["app_list"].sort(key=lambda app: sort(order.keys(),
            app["app_url"].strip("/").split("/")[-1]))
        for i, app in enumerate(context["app_list"]):
            # sort the model list for each app
            app_name = app["app_url"].strip("/").split("/")[-1]
            if not app_name:
                app_name = app["name"].lower()
            model_order = [m.lower() for m in order.get(app_name, [])]
            context["app_list"][i]["models"].sort(key=lambda model:
            sort(model_order, model["admin_url"].strip("/").split("/")[-1]))
    return ""

Settings.py内:

ADMIN_REORDER = (
    ('app1', ('App1Model1', 'App1Model2', 'App1Model3')),
    ('app2', ('App2Model1', 'App2Model2')),
)

(ここに独自のアプリ名を挿入します。各アプリに少なくとも2つのモデルをリストしている限り、管理者は不足しているアプリまたはモデルをリストの最後に配置します。)

Base_site.htmlのコピー:

{% extends "admin/base.html" %}
{% load i18n admin_reorder %}

{% block title %}{{ title }} | {% trans 'Django site admin' %}{% endblock %}

{% block branding %}
{% admin_reorder %}
<h1 id="site-name">{% trans 'Django administration' %}</h1>
{% endblock %}

{% block nav-global %}{% endblock %}
6
Rick Westera

2018年6月の回答

この答えは Vasilのアイデア に似ています

私は同様の問題を解決しようとしました、そしてそれから私はそのような フラグメント を見ました。

このクリップに基づいていくつかの変更を加えました。コードは次のとおりです。

# myproject/setting.py
...
# set my ordering list
ADMIN_ORDERING = [
    ('pizza_app', [
        'Pizzas',
        'Toppings'
    ]),
]
# Creating a sort function
def get_app_list(self, request):
    app_dict = self._build_app_dict(request)
    for app_name, object_list in ADMIN_ORDERING:
        app = app_dict[app_name]
        app['models'].sort(key=lambda x: object_list.index(x['object_name']))
        yield app


# Covering Django.contrib.admin.AdminSite.get_app_list
from Django.contrib import admin

admin.AdminSite.get_app_list = get_app_list
...

この並べ替え機能で使用される並べ替えリストには、システム内のすべてのアプリとそのモジュールの並べ替えが含まれていることに注意してください。不要な場合は、必要に応じてソート機能を設計してください。

Django 2.0でうまく機能します

5
林伟雄

また、 'Django Admin Index Custom App&Model Ordering'と呼ばれる小さなコードを使用することもできます。スニペットは、3つの簡単な編集で問題を解決します。

詳細はこちらをご覧ください。 http://djangosnippets.org/snippets/2613/

3
Fatih Axl

AdminSiteに Suit を使用している場合は、 menu tag を使用してメニューのカスタマイズを行うことができます。

2
melbic

管理パネルでアプリを名前で注文できる簡単なソリューションを探していました。私は次のテンプレートタグを思いついた:

from Django import template
from Django.conf import settings
register = template.Library()

@register.filter
def sort_apps(apps):
    apps.sort(
        key = lambda x:
        settings.APP_ORDER.index(x['app_label'])
        if x['app_label'] in settings.APP_ORDER
        else len(apps)
    )
    print [x['app_label'] for x in apps]
    return apps

次に、templates/admin/index.htmlをオーバーライドして、そのテンプレートタグを追加します。

{% extends "admin/index.html" %}
{% block content %}
{% load i18n static sort_apps %}
<div id="content-main">

{% if app_list %}
    {% for app in app_list|sort_apps %}
        <div class="app-{{ app.app_label }} module">
        <table>
        <caption>
            <a href="{{ app.app_url }}" class="section" title="{% blocktrans with name=app.name %}Models in the {{ name }} application{% endblocktrans %}">{{ app.name }}</a>
        </caption>
        {% for model in app.models %}
            <tr class="model-{{ model.object_name|lower }}">
            {% if model.admin_url %}
                <th scope="row"><a href="{{ model.admin_url }}">{{ model.name }}</a></th>
            {% else %}
                <th scope="row">{{ model.name }}</th>
            {% endif %}

            {% if model.add_url %}
                <td><a href="{{ model.add_url }}" class="addlink">{% trans 'Add' %}</a></td>
            {% else %}
                <td>&nbsp;</td>
            {% endif %}

            {% if model.admin_url %}
                <td><a href="{{ model.admin_url }}" class="changelink">{% trans 'Change' %}</a></td>
            {% else %}
                <td>&nbsp;</td>
            {% endif %}
            </tr>
        {% endfor %}
        </table>
        </div>
    {% endfor %}
{% else %}
    <p>{% trans "You don't have permission to edit anything." %}</p>
{% endif %}
</div>
{% endblock %}

次に、settings.pyのAPP_ORDERをカスタマイズしました。

APP_ORDER = [
    'app1',
    'app2',
    # and so on...
]

Django 1.10でうまく機能します

2
Jamie Counsell

Djangoのtracに追加しました:

http://code.djangoproject.com/ticket/9928

2
Rui Ferreira

lib\site-packages\Django\contrib\admin\templates\admin\index.htmlテンプレートをproject1\templates\admin\ディレクトリにコピーします。project1はプロジェクトの名前です。

コピーされたファイル、つまりproject1\templates\admin\index.htmlで、次の行を置き換えます。

{% block content %} 
...
{% endblock %}

と:

{% block content %}
<div id="content-main">

{% if app_list %}
    <div class="module">
        <table>
            <caption>App 1</caption>
            <tr>  <th>  <a href="/admin/app1/model1/">Model 1</a>  </th>  <td>Description of model 1</td>  </tr>
            <tr>  <th>  <a href="/admin/app1/model2/">Model 2</a>  </th>  <td>Description of model 1</td>  </tr>
            <tr>  <th>  <a href="..."                >...</a>      </th>  <td>...</td>                     </tr>
        </table>
    </div>

    <div class="module">
        <table>
            <caption>Authentication and authorization</caption>
            <tr>  <th>  <a href="/admin/auth/user/"  >Users</a>    </th>  <td>List of users</td>           </tr>
            <tr>  <th>  <a href="/admin/auth/group/" >Groups</a>   </th>  <td>List of users' groups</td>   </tr>
        </table>
    </div>
{% else %}
    <p>{% trans "You don't have permission to view or edit anything." %}</p>
{% endif %}

</div>
{% endblock %}  

どこ:

  • app1は、モデルを含むアプリケーションの名前です。
  • modeliは、app1のi番目のモデルの名前です。

プロジェクトでモデルを使用して複数のアプリケーションを定義した場合は、上記のindex.htmlファイルに別のテーブルを追加するだけです。

テンプレートを変更するため、HTMLコードを自由に変更できます。たとえば、上記のようにモデルの説明を追加できます。 AddおよびChangeリンクを復元することもできます-私はそれらを削除したのでそれらは冗長だと思います。

答えは Dave Kasperの答え からの解決策の実際的なデモンストレーションです。

0
iwis

これは、もう少し柔軟性を与えるバージョンです。つまり、次のとおりです。

  • アプリの順序を部分的に定義し、残りをDjangoに残してリストに追加することができます
  • 代わりに「*」を使用して、モジュールの順序を指定するか、定義を回避できます。
  • 定義したアプリの順序が最初に表示され、その後に残りのすべてのアプリが追加されます
  • アプリの名前を確認するには、アプリのディレクトリ内のファイル_apps.py_を確認し、class Config(AppConfi):のnameプロパティを確認するか、存在しない場合はディレクトリの名前を使用しますプロジェクト内のアプリの場合。

このコードを_settings.py_ファイルのどこかに追加します。

_# ======[Setting the order in which the apps/modules show up listed on Admin]========
# set my ordering list
ADMIN_ORDERING = [
    ('crm', '*'),
    ('property', '*'),
]


# Creating a sort function
def get_app_list(self, request):
    """
    Returns a sorted list of all the installed apps that have been
    registered in this site.

    Allows for:
        ADMIN_ORDERING = [
            ('app_1', [
                'module_1',
                'module_2'
            ]),
            ('app_2', '*'),
        ]
    """

    app_dict = self._build_app_dict(request)

    # Let's start by sorting the apps alphabetically on a list:
    app_list = sorted(app_dict.values(), key=lambda x: x['name'].lower())

    # Sorting the models alphabetically within each app.
    for app in app_list:
        if app['app_label'] in [el[0] for el in ADMIN_ORDERING]:
            app_list.remove(app)
        else:
            app['models'].sort(key=lambda x: x['name'])

    # Now we order the app list in our defined way in ADMIN_ORDERING (which could be a subset of all apps).
    my_ordered_apps = []
    if app_dict:
        for app_name, object_list in ADMIN_ORDERING:
            app = app_dict[app_name]
            if object_list == '*':
                app['models'].sort(key=lambda x: x['name'])
            else:
                app['models'].sort(key=lambda x: object_list.index(x['object_name']))
            my_ordered_apps.append(app)

        # Now we combine and arrange the 2 lists together
        my_ordered_apps.extend(app_list)

    return my_ordered_apps

# Covering Django.contrib.admin.AdminSite.get_app_list
from Django.contrib import admin
admin.AdminSite.get_app_list = get_app_list
# =========================================

_

これは、ファイルpython2.7/site-packages/Django/contrib/admin /sites.pyのDjangoで定義された関数を上書きするだけです。

class AdminSite(object):の_get_app_list_メソッドは、次のようなDjangoの認証アプリを含むプロジェクト上のすべてのアプリでデータ構造を生成します。

_[
  {
    "app_label": "auth",
    "app_url": "/admin/auth/",
    "has_module_perms": "True",
    "models": [
      {
        "add_url": "/admin/auth/group/add/",
        "admin_url": "/admin/auth/group/",
        "name": "<Django.utils.functional.__proxy__ object at 0x11057f990>",
        "object_name": "Group",
        "perms": {
          "add": "True",
          "change": "True",
          "delete": "True"
        }
      },
      {
        "add_url": "/admin/auth/user/add/",
        "admin_url": "/admin/auth/user/",
        "name": "<Django.utils.functional.__proxy__ object at 0x11057f710>",
        "object_name": "User",
        "perms": {
          "add": "True",
          "change": "True",
          "delete": "True"
        }
      }
    ],
    "name": "<Django.utils.functional.__proxy__ object at 0x108b81850>"
  },
  {
    "app_label": "reservations",
    "app_url": "/admin/reservations/",
    "has_module_perms": "True",
    "models": [
      {
        "add_url": "/admin/reservations/reservationrule/add/",
        "admin_url": "/admin/reservations/reservationrule/",
        "name": "<Django.utils.functional.__proxy__ object at 0x11057f6d0>",
        "object_name": "ReservationRule",
        "perms": {
          "add": "True",
          "change": "True",
          "delete": "True"
        }
      }
    ],
    "name": "Availability"
  },
  {
    "app_label": "blog",
    "app_url": "/admin/blog/",
    "has_module_perms": "True",
    "models": [
      {
        "add_url": "/admin/blog/category/add/",
        "admin_url": "/admin/blog/category/",
        "name": "Categories",
        "object_name": "Category",
        "perms": {
          "add": "True",
          "change": "True",
          "delete": "True"
        }
      },
      {
        "add_url": "/admin/blog/post/add/",
        "admin_url": "/admin/blog/post/",
        "name": "<Django.utils.functional.__proxy__ object at 0x11057f110>",
        "object_name": "Post",
        "perms": {
          "add": "True",
          "change": "True",
          "delete": "True"
        }
      },
      {
        "add_url": "/admin/blog/tag/add/",
        "admin_url": "/admin/blog/tag/",
        "name": "<Django.utils.functional.__proxy__ object at 0x11057f390>",
        "object_name": "Tag",
        "perms": {
          "add": "True",
          "change": "True",
          "delete": "True"
        }
      }
    ],
    "name": "Blog"
  },
(...)
]
_
0
Rui Carvalho

私の解決策は、Django.contrib.admin.sites.AdminSiteとDjango.contrib.admin.options.ModelAdminのサブクラスを作成することでした。

これを行ったのは、各アプリのよりわかりやすいタイトルを表示し、各アプリのモデルの外観を注文できるようにするためです。そのため、settings.pyに、app_labelsを説明的な名前とそれらが表示される順序にマップする辞書があります。モデルは、管理サイトに登録するときに各ModelAdminで指定する順序フィールドによって順序付けられます。

ドキュメントでは、AdminSiteとModelAdminの独自のサブクラスを作成することが推奨されていますが、私のソリューションは最終的には醜いハックのように見えます。

0
Vasil

これは暗闇の中での単なる刺し傷ですが、admin.site.register(<モデルクラス>、<ModelAdminクラス>)を呼び出す順序によって表示順序が決まる可能性はありますか?実際、私はそれがうまくいくとは思えません。Djangoはモデルのレジストリを維持している->標準として実装されているModelAdminオブジェクトPython反復順序。

それが希望どおりに動作しない場合は、Django/contrib/adminのソースをいつでも試すことができます。反復順序を維持する必要がある場合は、AdminSiteクラス(admin/sites.py内)の_registryオブジェクトを、キーの挿入順序を維持するUserDictまたはDictMixinに置き換えることができます。 (しかし、私はこの種の変更を自分で行ったことがなく、Django ModelAdminのコレクションを反復する方法についての知識に基づいた推測をしているだけなので、このアドバイスを一粒の塩で受けてくださいオブジェクト。Django/ contrib/admin/sites.pyがこのコードを探す場所だと思いますが、特にAdminSiteクラスとregister()およびindex()メソッドが必要です。)

明らかに、ここで最も優れているのは、独自の/admin.pyモジュールで指定する簡単なオプションです。それはあなたが受け取りたいと思っていた種類の答えだと確信しています。ただし、これらのオプションが存在するかどうかはわかりません。

0
Jeff