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
The author runs the application development company Cyberneura.
We look forward to discussing your development needs.

Archive

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