__unicode__書くの面倒。

問題

  1. djangoのモデルのデフォルトの表示がしょぼい
    1. オブジェクトの持つフィールドの値が分かんない。
    2. __unicode__メソッドを自分で書く必要がある。
  2. モデル毎に__unicode__を定義したくない。
    1. 面倒くさい
    2. デコレータとかでどうにかならない?
  3. でも、__unicode__を定義したモデルでは、そちらを使いたい。
    1. デコレータで__unicode__を上書きしたくない。

inspectableというデコレータを作成してみた*1

inspectable

こうやって使う。

defaultで__unicode__が定義される。
@inspectable
class Foo(models.Model):
   pass

定義された__unicode__は以下の機能を持っている。

  • 全部のフィールドを表示する

なので、python manage.py shellなどでどんな値が入っているのか調べやすい。

__unicode__が定義されているとinspectableは単に無視する(何もしない)
@inspectable
class Bar(models.Model):
   name = models.CharField(max_length=255)
   
   def __unicode__(self): #こちらが優先される。
       return u"%s" % self.name

まだ途中だけれど使用例。

# -*- coding:utf-8 -*-

## moduleのpath設定していないため
import sys
sys.path.append(".")

from common.misc.inspect import inspectable #これ使っている。

### sample
## ここから下は、django アプリを使わずにdjango.db.modelsのクラスを使うためにちょっとおまじないを加えてる。

from django.conf import settings 
settings.configure() 
import django.db.models as models
import types 
import sys


## ここらへんおまじない
_K = "_.sample.models"
sys.modules[_K] = types.ModuleType(_K)

@inspectable
class Item(models.Model):
    is_soldout = models.BooleanField(default=False)
    __module__ = _K # models.Base.newをごまかすため

    class Meta:
        abstract = True

    def __unicode__(self):
        return u">_< %s: %s" % (self.__class__.__name__, self.is_soldout)

@inspectable
class Author(models.Model):
    __module__ = _K # models.Base.newをごまかすため
    name = models.CharField(max_length=255)

@inspectable
class Book(Item):
    __module__ = _K # models.Base.newをごまかすため
    title = models.CharField(max_length=255)
    author = models.ForeignKey(Author, null=True)


### 利用
bm =  globals()["Item"]()
print bm
print Item(is_soldout=True)


print Book(is_soldout=True, title="hoo")
author = Author(name="fo")
author = Author(name=u"カルピス")
print Book(title="hoo", author=author)

出力結果

# python ~/myproject/django-model-inspect/sample.py
>_< Item: False
>_< Item: True
Book:
  is_soldout = True
  title = hoo
  author = None

Book:
  is_soldout = False
  title = hoo
  author = Author:
    name = カルピス

追記

_Kなど書いていたのは単なるおまじないです。これは実際のコードではまったく必要ありません。
おまじないを着けていたのは、django.db.modelsのクラスを使うのにdjangoアプリケーションを作るのが面倒だったからです。
これはどういうことかというと,

python manage.py startapp foo
vim foo/models.py #ここでmodelを定義(普通は)

というのがめんどうだったからです。おまじないを書いたのは、これを単にpythonスクリプトと同様の形式で呼びたかったからです。
単なる横着です。以下のおまじないを含むコードは、その後とおまじないを含まないコードと対応します。
(そして、このおまじないは実際のコードではまったく必要ありません。)

横着のためのおまじないを含んだコード

from django.conf import settings 
settings.configure() 
import django.db.models as models
import sys

_K = "_.sample.models"
sys.modules[_K] = types.ModuleType(_K)

class Item(models.Model):
    is_soldout = models.BooleanField(default=False)
    __module__ = _K # models.Base.newをごまかすため

    def __unicode__(self):
        return u"s: %s" % (self.__class__.__name__, self.is_soldout)

実際に必要なコード(普通はこちらで十分)

import django.db.models as models

class Item(models.Model):
    is_soldout = models.BooleanField(default=False)

    def __unicode__(self):
        return u"%s: %s" % (self.__class__.__name__, self.is_soldout)

*1:inspired by ruby's Object#inspect