Commit a553789b authored by Gabriel Detraz's avatar Gabriel Detraz Committed by chirac

Draft : on save que si l'objet a été modifié

parent 30a576c0
......@@ -38,7 +38,7 @@ class FormRevMixin(object):
def save(self, *args, **kwargs):
if reversion.get_comment() != "" and self.changed_data != []:
reversion.set_comment(reversion.get_comment() + ",%s" % ', '.join(field for field in self.changed_data))
elif self.changed_data != None:
elif self.changed_data:
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in self.changed_data))
return super(FormRevMixin, self).save(*args, **kwargs)
# -*- coding: utf-8 -*-
import sys
import json
import six
from django.conf import settings
from import BaseCommand, CommandError
from import ModelGraph, generate_dot
from import signalcommand
import pygraphviz
except ImportError:
import pydotplus as pydot
except ImportError:
import pydot
except ImportError:
class Command(BaseCommand):
help = "Creates a GraphViz dot file for the specified app names. You can pass multiple app names and they will all be combined into a single model. Output is usually directed to a dot file."
can_import_settings = True
def __init__(self, *args, **kwargs):
"""Allow defaults for arguments to be set in settings.GRAPH_MODELS.
Each argument in self.arguments is a dict where the key is the
space-separated args and the value is our kwarg dict.
The default from settings is keyed as the long arg name with '--'
removed and any '-' replaced by '_'.
self.arguments = {
'--pygraphviz': {
'action': 'store_true', 'dest': 'pygraphviz',
'help': 'Use PyGraphViz to generate the image.'},
'--pydot': {'action': 'store_true', 'dest': 'pydot',
'help': 'Use PyDot(Plus) to generate the image.'},
'--disable-fields -d': {
'action': 'store_true', 'dest': 'disable_fields',
'help': 'Do not show the class member fields'},
'--group-models -g': {
'action': 'store_true', 'dest': 'group_models',
'help': 'Group models together respective to their '
'--all-applications -a': {
'action': 'store_true', 'dest': 'all_applications',
'help': 'Automatically include all applications from '
'--output -o': {
'action': 'store', 'dest': 'outputfile',
'help': 'Render output file. Type of output dependend on file '
'extensions. Use png or jpg to render graph to image.'},
'--layout -l': {
'action': 'store', 'dest': 'layout', 'default': 'dot',
'help': 'Layout to be used by GraphViz for visualization. '
'Layouts: circo dot fdp neato nop nop1 nop2 twopi'},
'--verbose-names -n': {
'action': 'store_true', 'dest': 'verbose_names',
'help': 'Use verbose_name of models and fields'},
'--language -L': {
'action': 'store', 'dest': 'language',
'help': 'Specify language used for verbose_name localization'},
'--exclude-columns -x': {
'action': 'store', 'dest': 'exclude_columns',
'help': 'Exclude specific column(s) from the graph. '
'Can also load exclude list from file.'},
'--exclude-models -X': {
'action': 'store', 'dest': 'exclude_models',
'help': 'Exclude specific model(s) from the graph. Can also '
'load exclude list from file. Wildcards (*) are allowed.'},
'--include-models -I': {
'action': 'store', 'dest': 'include_models',
'help': 'Restrict the graph to specified models. Wildcards '
'(*) are allowed.'},
'--inheritance -e': {
'action': 'store_true', 'dest': 'inheritance', 'default': True,
'help': 'Include inheritance arrows (default)'},
'--no-inheritance -E': {
'action': 'store_false', 'dest': 'inheritance',
'help': 'Do not include inheritance arrows'},
'--hide-relations-from-fields -R': {
'action': 'store_false', 'dest': 'relations_as_fields',
'default': True,
'help': 'Do not show relations as fields in the graph.'},
'--disable-sort-fields -S': {
'action': 'store_false', 'dest': 'sort_fields',
'default': True, 'help': 'Do not sort fields'},
'--json': {'action': 'store_true', 'dest': 'json',
'help': 'Output graph data as JSON'}
defaults = getattr(settings, 'GRAPH_MODELS', None)
if defaults:
for argument in self.arguments:
arg_split = argument.split(' ')
setting_opt = arg_split[0].lstrip('-').replace('-', '_')
if setting_opt in defaults:
self.arguments[argument]['default'] = defaults[setting_opt]
super(Command, self).__init__(*args, **kwargs)
def add_arguments(self, parser):
"""Unpack self.arguments for parser.add_arguments."""
parser.add_argument('app_label', nargs='*')
for argument in self.arguments:
parser.add_argument(*argument.split(' '),
def handle(self, *args, **options):
args = options['app_label']
if len(args) < 1 and not options['all_applications']:
raise CommandError("need one or more arguments for appname")
use_pygraphviz = options.get('pygraphviz', False)
use_pydot = options.get('pydot', False)
use_json = options.get('json', False)
if use_json and (use_pydot or use_pygraphviz):
raise CommandError("Cannot specify --json with --pydot or --pygraphviz")
cli_options = ' '.join(sys.argv[2:])
graph_models = ModelGraph(args, cli_options=cli_options, **options)
graph_data = graph_models.get_graph_data(as_json=use_json)
if use_json:
self.render_output_json(graph_data, **options)
dotdata = generate_dot(graph_data)
if not six.PY3:
dotdata = dotdata.encode('utf-8')
if options['outputfile']:
if not use_pygraphviz and not use_pydot:
use_pygraphviz = True
use_pydot = True
if use_pygraphviz:
self.render_output_pygraphviz(dotdata, **options)
elif use_pydot:
self.render_output_pydot(dotdata, **options)
raise CommandError("Neither pygraphviz nor pydotplus could be found to generate the image")
def print_output(self, dotdata):
if six.PY3 and isinstance(dotdata, six.binary_type):
dotdata = dotdata.decode()
def render_output_json(self, graph_data, **kwargs):
output_file = kwargs.get('outputfile')
if output_file:
with open(output_file, 'wt') as json_output_f:
json.dump(graph_data, json_output_f)
def render_output_pygraphviz(self, dotdata, **kwargs):
"""Renders the image using pygraphviz"""
raise CommandError("You need to install pygraphviz python module")
version = pygraphviz.__version__.rstrip("-svn")
if tuple(int(v) for v in version.split('.')) < (0, 36):
# HACK around old/broken AGraph before version 0.36 (ubuntu ships with this old version)
import tempfile
tmpfile = tempfile.NamedTemporaryFile()
dotdata =
except ValueError:
graph = pygraphviz.AGraph(dotdata)
def render_output_pydot(self, dotdata, **kwargs):
"""Renders the image using pydot"""
if not HAS_PYDOT:
raise CommandError("You need to install pydot python module")
graph = pydot.graph_from_dot_data(dotdata)
if not graph:
raise CommandError("pydot returned an error")
if isinstance(graph, (list, tuple)):
if len(graph) > 1:
sys.stderr.write("Found more then one graph, rendering only the first one.\n")
graph = graph[0]
output_file = kwargs['outputfile']
formats = ['bmp', 'canon', 'cmap', 'cmapx', 'cmapx_np', 'dot', 'dia', 'emf',
'em', 'fplus', 'eps', 'fig', 'gd', 'gd2', 'gif', 'gv', 'imap',
'imap_np', 'ismap', 'jpe', 'jpeg', 'jpg', 'metafile', 'pdf',
'pic', 'plain', 'plain-ext', 'png', 'pov', 'ps', 'ps2', 'svg',
'svgz', 'tif', 'tiff', 'tk', 'vml', 'vmlz', 'vrml', 'wbmp', 'xdot']
ext = output_file[output_file.rfind('.') + 1:]
format = ext if ext in formats else 'raw'
graph.write(output_file, format=format)
This diff is collapsed.
......@@ -279,8 +279,9 @@ def edit_port(request, port_object, portid):
port = EditPortForm(request.POST or None, instance=port_object)
if port.is_valid():
messages.success(request, "Le port a bien été modifié")
if port.changed_data:
messages.success(request, "Le port a bien été modifié")
return redirect(reverse(
kwargs={'switchid': str(}
......@@ -323,8 +324,9 @@ def edit_stack(request, stack, stackid):
"""Edition d'un stack (nombre de switches, nom...)"""
stack = StackForm(request.POST or None, instance=stack)
if stack.is_valid():
return redirect(reverse('topologie:index-stack'))
if stack.changed_data:
return redirect(reverse('topologie:index-stack'))
return form({'topoform': stack, 'action_name' : 'Editer'}, 'topologie/topo.html', request)
......@@ -463,9 +465,12 @@ def edit_switch(request, switch, switchid):
new_switch =
new_interface_instance =
new_domain =
if switch_form.changed_data:
if interface_form.changed_data:
if domain_form.changed_data:
messages.success(request, "Le switch a bien été modifié")
return redirect(reverse('topologie:index'))
i_mbf_param = generate_ipv4_mbf_param(interface_form, False )
......@@ -553,9 +558,12 @@ def edit_ap(request, ap, accesspointid):
new_ap =
new_interface =
new_domain =
if ap_form.changed_data:
if interface_form.changed_data:
if domain_form.changed_data:
messages.success(request, "La borne a été modifiée")
return redirect(reverse('topologie:index-ap'))
i_mbf_param = generate_ipv4_mbf_param(interface_form, False )
......@@ -586,8 +594,9 @@ def edit_room(request, room, roomid):
""" Edition numero et details de la chambre"""
room = EditRoomForm(request.POST or None, instance=room)
if room.is_valid():
messages.success(request, "La chambre a bien été modifiée")
if room.changed_data:
messages.success(request, "La chambre a bien été modifiée")
return redirect(reverse('topologie:index-room'))
return form({'topoform': room, 'action_name' : 'Editer'}, 'topologie/topo.html', request)
......@@ -629,8 +638,9 @@ def edit_model_switch(request, model_switch, modelswitchid):
model_switch = EditModelSwitchForm(request.POST or None, instance=model_switch)
if model_switch.is_valid():
messages.success(request, "Le modèle a bien été modifié")
if model_switch.changed_data:
messages.success(request, "Le modèle a bien été modifié")
return redirect(reverse('topologie:index-model-switch'))
return form({'topoform': model_switch, 'action_name' : 'Editer'}, 'topologie/topo.html', request)
......@@ -672,8 +682,9 @@ def edit_constructor_switch(request, constructor_switch, constructorswitchid):
constructor_switch = EditConstructorSwitchForm(request.POST or None, instance=constructor_switch)
if constructor_switch.is_valid():
messages.success(request, "Le modèle a bien été modifié")
if constructor_switch.changed_data:
messages.success(request, "Le modèle a bien été modifié")
return redirect(reverse('topologie:index-model-switch'))
return form({'topoform': constructor_switch, 'action_name' : 'Editer'}, 'topologie/topo.html', request)
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment