verbose_nameの取得

1,116 views
Skip to first unread message

Sumiya Sakoda

unread,
Sep 21, 2008, 3:26:29 AM9/21/08
to django-ja
佐古田です。
バージョン0.96から1.0への移行作業をしておりちょっと質問があります。

テンプレート上でモデルのverbose_nameを取得したく、旧バージョンではtemplatetagsにて

Item.AddManipulator().opts.verbose_name

としていました。1.0ではAddManipulatorがないようなのでadmin下のソースを探って

Item._meta.verbose_name

という形で一応取得できたように思います。

ここで質問ですが、ハイフンで始まるプライベートメンバのようで気色悪いのですが、これで正しいのでしょうか。
もっとまっとうな方法がございますか。

Yasushi Masuda

unread,
Sep 21, 2008, 7:07:00 AM9/21/08
to djan...@googlegroups.com
佐古田さん

verbose_name をモデルクラスから直接取り出したければ、 _meta を参照するしか
方法はないと思います。ただし、verbose_name に限って言えば、
django.contrib.contenttypes.ContentType.name を使えば verbose_name を得られます::

from django.contrib.contenttypes.models import ContentType
from yourapp.models import YourModel

...
def yourview(request):
ct = ContentType.objects.get_for_model(YourModel)
...
return HttpResponse(Template('{% load i18n %}{% trans ct.name %}').render(Context(dict(ct=ct))))

翻訳前の値なので、明示的に翻訳が必要です。

---
Yasushi Masuda
http://ymasuda.jp/

Sumiya Sakoda さんは書きました:

Sumiya Sakoda

unread,
Sep 21, 2008, 7:21:08 AM9/21/08
to django-ja
増田さんありがとうございます。

On 9月21日, 午後8:07, Yasushi Masuda <ymas...@ethercube.com> wrote:

> verbose_name をモデルクラスから直接取り出したければ、 _meta を参照するしか
> 方法はないと思います。ただし、verbose_name に限って言えば、
> django.contrib.contenttypes.ContentType.name を使えば verbose_name を得られます::

実際verbose_nameくらいしか使うことがないのでご教示いただいた方法のほうがいい感じです。

> 翻訳前の値なので、明示的に翻訳が必要です。

ここはちょっと見落としそうでした。
どうもありがとうございました。気になった点は解決しました。

# まだまだバージョンアップへの道は険しいですが。

Sumiya Sakoda

unread,
Sep 21, 2008, 6:36:18 PM9/21/08
to django-ja
佐古田です。
別件で詰まってましてひょっとして今回の件とも関係あるかなと思って追加質問です。

> > 翻訳前の値なので、明示的に翻訳が必要です。

ふむふむと思いながら実際のところverbose_nameは日本語を使っていたので翻訳する必要がありませんでした。
ところがverbose_nameに日本語を使うと弊害が発生していることに気づきました。

1. modelのMetaクラスのverbose_nameを日本語で定義する。

class Item(models.Model):
....
class Meta:
verbose_name = "商品"
verbose_name_plural = "商品"

2. auth_permissionに以下のデータが挿入される。

Can add 商品
Can change 商品
Can delete 商品

3. 管理画面のユーザやグループの登録でパーミッションのリストボックスが非表示になり選択できなくなる。

3の状態になるので悩んでいてなぜなるのかと調べたら上記手順のせいだったかなと思います。
0.96の時は日本語でもOKでしたが1.0ではverbose_nameはマルチバイト文字は使わず翻訳を利用するのが流儀なのでしょうか。
もしそうであるならばドキュメントとしてはどのあたりに定義されていますか?

- sS

Yasushi Masuda

unread,
Sep 21, 2008, 8:23:40 PM9/21/08
to djan...@googlegroups.com
佐古田さん

翻訳を使わなければならないとか、 ascii でなければならない、といった
流儀はなかったように思います。挙動をみるかぎり、パーミッションのテーブルから
レコードを取り出そうとしてエラーを起こしているようですね。
お使いのバックエンドのレベルで (manage.py shell/dbshell で) パーミッション
テーブルを select できますか?あと、実際のコードでは verbose_name を unicode
リテラルでマークアップしていますでしょうか?

---
Yasushi Masuda
http://ymasuda.jp/

Sumiya Sakoda さんは書きました:

Sumiya Sakoda

unread,
Sep 21, 2008, 9:42:01 PM9/21/08
to django-ja
増田さんありがとうございます。

On 9月22日, 午前9:23, Yasushi Masuda <ymas...@ethercube.com> wrote:

> 翻訳を使わなければならないとか、 ascii でなければならない、といった
> 流儀はなかったように思います。挙動をみるかぎり、パーミッションのテーブルから
> レコードを取り出そうとしてエラーを起こしているようですね。
> お使いのバックエンドのレベルで (manage.py shell/dbshell で) パーミッション
> テーブルを select できますか?あと、実際のコードでは verbose_name を unicode
> リテラルでマークアップしていますでしょうか?

manage.py dbshellではselectできます。
(環境: MySQL 5.0.32-Debian_7etch5-log, 文字セット: UTF-8 Unicode (utf8) )

manage.py shellは日本語がはいっているところでこけます。
>>> from django.contrib.auth.models import Permission
>>> for a in Permission.objects.all():
... print a
...
admin | log entry | Can add log entry
admin | log entry | Can change log entry
(略)
Traceback (most recent call last):
File "<console>", line 2, in ?
File "/usr/lib/python2.4/site-packages/django/db/models/base.py",
line 273, in __str__
return force_unicode(self).encode('utf-8')
File "/usr/lib/python2.4/site-packages/django/utils/encoding.py",
line 70, in force_unicode
raise DjangoUnicodeDecodeError(s, *e.args)
DjangoUnicodeDecodeError: <unprintable instance object>

unicode リテラルでマークアップの件ですが、いずれもだめです。
(環境: マシンのロケールja_JP.UTF-8, pythonのデフォルトエンコーディング ascii, model.pyの文字コード
utf-8)

verbose_name = u'商品'
verbose_name_plural = u'商品'
または
verbose_name = unicode('商品', 'utf-8')
verbose_name_plural = unicode('商品', 'utf-8')

何年使ってても文字コードまわりの理解が発展しないので何か勘違いしていますでしょうか?

- sS

Yasushi Masuda

unread,
Sep 22, 2008, 12:29:29 AM9/22/08
to djan...@googlegroups.com
佐古田さん

いい機会だったので、ちょっと mysql を入れて調べてみました。 u'商品' でうまく動きました。
(デフォルトのインストールで character set が latin1 に設定されてうまくいかなかったので
my.cnf で utf8 に設定しました。)

### テーブルを作成します。

herring:demo1 ymasuda$ /usr/local/mysql/bin/mysqladmin create demo20080922

### 文字セットは utf8 です。

herring:demo1 ymasuda$ /usr/local/mysql/bin/mysql
...
mysql> \s demo20080922
--------------
/usr/local/mysql/bin/mysql Ver 14.12 Distrib 5.0.67, for apple-darwin9.0.0b5 (i686) using readline 5.1

Connection id: 155
Current database:
Current user: ymasuda@localhost
SSL: Not in use
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server version: 5.0.67 MySQL Community Server (GPL)
Protocol version: 10
Connection: Localhost via UNIX socket
Server characterset: utf8
Db characterset: utf8
Client characterset: utf8
Conn. characterset: utf8
UNIX socket: /tmp/mysql.sock
Uptime: 5 min 1 sec
...
-> \q
Bye

### syncdb でテーブルを生成します。

herring:demo1 ymasuda$ ./manage.py syncdb
Creating table auth_permission
...
Creating table s_item
...
Installing index for auth.Permission model
...

### dbshell で確認すると、 s_item モデルテーブルができています。

herring:demo1 ymasuda$ ./manage.py dbshell
...
mysql> show tables;
+----------------------------+
| Tables_in_demo20080922 |
+----------------------------+
...
| s_item |
+----------------------------+
12 rows in set (0.00 sec)

### パーミッションテーブルのレコードを問題なく取り出せます。

mysql> select * from auth_permission;
+----+-------------------------+-----------------+--------------------+
| id | name | content_type_id | codename |
+----+-------------------------+-----------------+--------------------+
...
| 25 | Can add 商品 | 9 | add_item |
| 26 | Can change 商品 | 9 | change_item |
| 27 | Can delete 商品 | 9 | delete_item |
+----+-------------------------+-----------------+--------------------+
27 rows in set (0.00 sec)

mysql> \q
Bye

### shell を起動して Permission オブジェクトを取り出してみます。

herring:demo1 ymasuda$ ./manage.py shell
...
In [1]: from django.contrib.auth.models import *

In [2]: Permission.objects.all()

Out[2]: [<... <Permission: s | 商品 | Can add 商品>, <Permission: s | 商品 | Can change 商品>, <Permission: s | 商品 | Can delete 商品>, ...]
...

In [5]: Permission.objects.all()[19]

Out[5]: <Permission: s | 商品 | Can change 商品>

In [6]: Permission.objects.all()[19].name

Out[6]: u'Can change \u5546\u54c1'

...

### コンテンツタイプの verbose_name を取り出します。

In [11]: Permission.objects.all()[19].content_type.name

Out[11]: u'\u5546\u54c1'

In [12]: print Permission.objects.all()[19].content_type.name
商品

(この時点で、 http://localhost:8000/admin/auth/user/add/ でユーザを
追加した **後**, パーミッションを操作できます)

Python の文字コードというよりも、 MySQL とか MySQLdb の問題で
エラーを引き起こしているのかもしれません。
手元の MySQLdb のバージョンは 1.2.2 です。DATABASE_OPTIONSは使っていません。

---
Yasushi Masuda
http://ymasuda.jp/

Sumiya Sakoda さんは書きました:

Sumiya Sakoda

unread,
Sep 22, 2008, 12:54:27 AM9/22/08
to django-ja
増田さん、ご丁寧な検証ありがとうございました。

On 9月22日, 午後1:29, Yasushi Masuda <ymas...@ethercube.com> wrote:

> いい機会だったので、ちょっと mysql を入れて調べてみました。 u'商品' でうまく動きました。
> (デフォルトのインストールで character set が latin1 に設定されてうまくいかなかったので
> my.cnf で utf8 に設定しました。)

(以下略)

時間見て自分でも同様の検証してみます。Djangoの問題でないであろうという結果が出ただけでも問題が絞り込みやすくなりました。

> Python の文字コードというよりも、 MySQL とか MySQLdb の問題で
> エラーを引き起こしているのかもしれません。
> 手元の MySQLdb のバージョンは 1.2.2 です。DATABASE_OPTIONSは使っていません。

MySQLdbは確かに微妙なバージョンの差異で影響を及ぼした記憶があります。
ちなみに私のも1.2.2だったのでMySQLの設定が怪しいかもしれません。

問題はすぐに解決しないかもしれませんけれども、とりあえずマルチバイトのverbose_nameは定義せず翻訳で対応するか、ひょっとしたら
permission定義後はマルチバイトOKなのかまあ応急処置で対処します。

また結果などが出れば報告します。どうもありがとうございました。

- sS

Sumiya Sakoda

unread,
Sep 22, 2008, 6:22:32 AM9/22/08
to django-ja
佐古田です。

1日中奮闘していてなんとなく解決したような気がします。
おなじプログラムがsqliteでは問題なかったので明らかにMySQLまわりでした。

今まで新規にデータベースを作成するときは以下のようにやっていました。

CREATE DATABASE <dbname> DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;

あまり深い意味も考えていなかったのでunicode対応がこれでばっちりだと疑いもしてませんでした。
しかしdjangoのことはdjangoに聞けということで

http://docs.djangoproject.com/en/dev/ref/databases/

に記載されている

CREATE DATABASE <dbname> CHARACTER SET utf8;

をやってみて簡単なアプリケーションで試してみたらこれまで問題になっていた文字コード周りのこと(verbose_name他)が解決しました(と思
います)。
もう疲れたので今日は終わりにします。

いろいろご助言くださった増田さんありがとうございました。

- sS
Reply all
Reply to author
Forward
0 new messages