# -*- 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__)
コメント