モデルのリレーションを可視化するマネジメントコマンド

(コメント)

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

"""
モデルのリレーションを可視化するDjangoマネジメントコマンド
management/commands/view_models_relation.py

./manage.py view_models_relation

+ django.contrib.auth.models.Group
+ django.contrib.auth.models.User
| + django.contrib.auth.models.Message
| + django.contrib.admin.models.LogEntry
+ django.contrib.contenttypes.models.ContentType
| + django.contrib.auth.models.Permission
| + django.contrib.admin.models.LogEntry
+ django.contrib.sessions.models.Session
+ django.contrib.sites.models.Site
+ south.models.MigrationHistory
"""

from optparse import make_option
from django.core.management.base import BaseCommand
from django.db import models
from django.utils.encoding import smart_str
from django.conf import settings
from django.utils.importlib import import_module

class Command(BaseCommand):
    help = 'print model relation'
    args = '<app_name>'
    
    option_list = BaseCommand.option_list + (
        make_option('--verbose',
            action='store_true',
            dest='verbose',
            default=False,
            help=u'メッセージ出力の冗長化'),
    )
    
    def echo(self, message):
        """
        例: self.echo(self.style.NOTICE('NG!'))
        """
        self.stdout.write(smart_str(message, errors='ignore'))
        self.stdout.write('\n')
        self.stdout.flush()
    
    def echo_verbose(self, message):
        if self._verbose:
            return self.echo(message)
    
    def handle(self, app_label=None, **options):
        
        self._verbose=options.get('verbose', False)
        
        # APPをインポート
        for app_name in settings.INSTALLED_APPS:
            try:
                import_module('.management', app_name)
            except ImportError, exc:
                msg = exc.args[0]
                if not msg.startswith('No module named') or 'management' not in msg:
                    raise
        
        if app_label:
            app_list = [models.get_app(app_label)]
        else:
            app_list = models.get_apps()
        
        self.childs_dict = {} #自分の子の一覧を持つ
        #self.parents_dict = {} #自分の親の一覧を持つ
        primitive_models = [] #リレーションが全くない
        for app in app_list:
            if not app_label:
                self.echo_verbose('=' * 50)
                self.echo_verbose('App: %s' % app)
            
            app_models = models.get_models(app)
            
            if not app_models:
                self.echo_verbose('No app models.')
            
            for app_model in app_models:
                self.echo_verbose('-' * 50)
                app_model_name = self.get_model_path(app_model)
                self.echo_verbose('app_model_name=%s' % app_model_name)
                has_parent = False
                for field in app_model._meta.fields:
                    field_class_name = field.__class__.__name__
                    if field_class_name == 'ForeignKey' or \
                        field_class_name == 'OneToOneField' or \
                        field_class_name == 'ManyToManyField':
                        self.echo_verbose('related_field: %s' % field.name)
                        related_model = field.related.parent_model
                        rmn = self.get_model_path(related_model)
                        self.echo_verbose('related_model: %s' % rmn)
                        self.append_dict_list(self.childs_dict, rmn, app_model_name)
                        #self.append_dict_list(self.parents_dict, app_model_name, rmn)
                        has_parent = True
                if not has_parent:
                    primitive_models.append(app_model_name)
        
        for primitive_model in primitive_models:
            self.print_child(primitive_model)
    
    def print_child(self, model_name, depth=0):
        indent = ("|  " * depth)
        self.echo(indent +"+ "+ model_name)
        if model_name in self.childs_dict:
            child_models = self.childs_dict[model_name]
            for child_model in child_models:
                if child_model == model_name:
                    self.echo(indent +"+ " + child_model + " (self relation)")
                else:
                    self.print_child(child_model, depth=depth+1)
    
    def append_dict_list(self, d, k, v):
        """
        辞書 d は、valueにリストを持つ。
        そのリストに項目を追加。無ければ新規にリストを作る
        """
        if k in d:
            d[k].append(v)
        else:
            d[k] = [v]

    def get_model_path(self, model_class):
        return "%s.%s" % (model_class.__module__, model_class.__name__)
現在未評価

コメント

最近のツイート

  • ytyng

    ytyng @ytyng

    俺もスタバアプリにログインできないよ
    2 ヶ月, 1 週間 前

  • 安藤拓郎 Takuro Ando

    安藤拓郎 Takuro Ando @takuroando

    ytyng

    これまでいろんなグッズを作ってきたけど、今回は「お米」と聞いて買うしかないなと。今夜の夕食はコシヒカリ!箸もセットだし^^ https://t.co/01ucQx9qtw #腰乃展 #マンガ展 https://t.co/4VL2vOe0Og
    2 ヶ月, 3 週間 前

  • ytyng

    ytyng @ytyng

    講談社さんとやった全部入り電子書籍セットがギネスブックに登録されたよー https://t.co/rbkd3IYub0
    2 ヶ月, 3 週間 前