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

投稿者: ytyng 12 年, 9 ヶ月 前
# -*- 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__)
現在未評価

コメント

アーカイブ

2024
2023
2022
2021
2020
2019
2018
2017
2016
2015
2014
2013
2012
2011