Management Command to Visualize Model Relationships

Django
2011-06-17 16:09 (13 years ago) ytyng
# -*- coding: utf-8 -*-

"""
Django management command to visualize model relations
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='Verbose message output'),
    )

    def echo(self, message):
        """
        Example: 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)

        # Import APP
        for app_name in settings.INSTALLED_APPS:
            try:
                import_module('.management', app_name)
            except ImportError as 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 = {} # List of children
        #self.parents_dict = {} # List of parents
        primitive_models = [] # No relations at all
        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):
        """
        Dictionary d has a list as its value.
        Add an item to that list. If it doesn't exist, create a new list.
        """
        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__)
Currently unrated

Comments

Archive

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