トッピングクラスとピザクラスを備えたピザアプリケーションがあり、それらがDjango管理者のように表示されているとします:
PizzaApp
-
Toppings >>>>>>>>>> Add / Change
Pizzas >>>>>>>>>> Add / Change
しかし、私はそれらをこのようにしたいと思います:
PizzaApp
-
Pizzas >>>>>>>>>> Add / Change
Toppings >>>>>>>>>> Add / Change
Admin.pyでそれを構成するにはどうすればよいですか?
これは実際には Djangoチュートリアル のパート2)の一番下で説明されています。
関連するセクションは次のとおりです。
管理者インデックスページをカスタマイズします
同様に、Django管理者インデックスページのルックアンドフィールをカスタマイズすることもできます。
デフォルトでは、管理アプリケーションに登録されているINSTALLED_APPS内のすべてのアプリがアルファベット順に表示されます。レイアウトに大幅な変更を加えることができます。結局のところ、インデックスはおそらく管理者の最も重要なページであり、使いやすいはずです。
カスタマイズするテンプレートはadmin/index.htmlです。 (前のセクションのadmin/base_site.htmlと同じように、デフォルトのディレクトリからカスタムテンプレートディレクトリにコピーします。)ファイルを編集すると、app_listというテンプレート変数が使用されていることがわかります。この変数には、インストールされているすべてのDjangoアプリが含まれています。これを使用する代わりに、オブジェクト固有の管理ページへのリンクを最適な方法でハードコーディングできます。
試すことができる回避策は、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:この回答の投稿が遅すぎた場合は申し訳ありませんが、将来の同様の状況で他の人を助けることができます。
これを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
もちろん、それはエレガントではありませんが、より良い解決策が得られるまでしばらくは機能する可能性があります。
私は最終的にこれのおかげでそれを行うことができました Djangoスニペット 、あなたはADMIN_REORDER
設定に注意する必要があります:
ADMIN_REORDER = (
('app1', ('App1Model1', 'App1Model2', 'App1Model3')),
('app2', ('App2Model1', 'App2Model2')),
)
app1
の前にプロジェクト名を付けることはできません。つまり、app1
の代わりにmysite.app1
を使用してください。
そのための素敵なDjangoパッケージがあります:
これが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 %}
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でうまく機能します
また、 'Django Admin Index Custom App&Model Ordering'と呼ばれる小さなコードを使用することもできます。スニペットは、3つの簡単な編集で問題を解決します。
詳細はこちらをご覧ください。 http://djangosnippets.org/snippets/2613/
管理パネルでアプリを名前で注文できる簡単なソリューションを探していました。私は次のテンプレートタグを思いついた:
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> </td>
{% endif %}
{% if model.admin_url %}
<td><a href="{{ model.admin_url }}" class="changelink">{% trans 'Change' %}</a></td>
{% else %}
<td> </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でうまく機能します
Djangoのtracに追加しました:
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の答え からの解決策の実際的なデモンストレーションです。
これは、もう少し柔軟性を与えるバージョンです。つまり、次のとおりです。
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"
},
(...)
]
_
私の解決策は、Django.contrib.admin.sites.AdminSiteとDjango.contrib.admin.options.ModelAdminのサブクラスを作成することでした。
これを行ったのは、各アプリのよりわかりやすいタイトルを表示し、各アプリのモデルの外観を注文できるようにするためです。そのため、settings.pyに、app_labelsを説明的な名前とそれらが表示される順序にマップする辞書があります。モデルは、管理サイトに登録するときに各ModelAdminで指定する順序フィールドによって順序付けられます。
ドキュメントでは、AdminSiteとModelAdminの独自のサブクラスを作成することが推奨されていますが、私のソリューションは最終的には醜いハックのように見えます。
これは暗闇の中での単なる刺し傷ですが、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モジュールで指定する簡単なオプションです。それはあなたが受け取りたいと思っていた種類の答えだと確信しています。ただし、これらのオプションが存在するかどうかはわかりません。