Repository: django-extensions/django-extensions

Issue:
graph_models doesn't handle unicode verbose_names correctly
When using the `-n` flag in `graph_models` to use the `verbose_name`s of the models and fields, it doesn't handle unicode strings properly when they contain _actual_ non-ascii characters.
## How to reproduce the error

```
mkdir test_extensions
cd test_extensions/
mkvirtualenv test_extensions
pip install django django_extensions pygraphviz
django-admin startproject test_extensions .
./manage.py startapp test_app
```

Now add the following to `test_app/models.py`:

``` python
class MyTestModel(models.Model):

    year = models.PositiveIntegerField(
        verbose_name= u'Año'
    )

    class Meta:
        verbose_name = u"MyTestModel with año"
        verbose_name_plural = u"MyTestModels with año"
```

Add `django_extensions` to `INSTALLED_APPS` and then try to run:

```
./manage.py graph_models -g -o myapp_models.png -R -S -n -a
```

This is the error that appears:

```
Traceback (most recent call last):
  File "./manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/home/jose/.virtualenvs/test_extensions/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 338, in execute_from_command_line
    utility.execute()
  File "/home/jose/.virtualenvs/test_extensions/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 330, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/home/jose/.virtualenvs/test_extensions/local/lib/python2.7/site-packages/django/core/management/base.py", line 393, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/home/jose/.virtualenvs/test_extensions/local/lib/python2.7/site-packages/django/core/management/base.py", line 444, in execute
    output = self.handle(*args, **options)
  File "/home/jose/.virtualenvs/test_extensions/local/lib/python2.7/site-packages/django_extensions/management/utils.py", line 57, in inner
    ret = func(self, *args, **kwargs)
  File "/home/jose/.virtualenvs/test_extensions/local/lib/python2.7/site-packages/django_extensions/management/commands/graph_models.py", line 77, in handle
    dotdata = generate_dot(args, cli_options=cli_options, **options)
  File "/home/jose/.virtualenvs/test_extensions/local/lib/python2.7/site-packages/django_extensions/management/modelviz.py", line 141, in generate_dot
    model['label'] = appmodel._meta.verbose_name.decode("utf8")
  File "/home/jose/.virtualenvs/test_extensions/lib/python2.7/encodings/utf_8.py", line 16, in decode
    return codecs.utf_8_decode(input, errors, True)
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf1' in position 18: ordinal not in range(128)
```

If you try to run the same command **without** the `-n` flag, the problem disappears.

Looks like the problem lies in the `modelviz.py` file, where the `verbose_name` strings are not properly handled.



Discussion:

Resolving patch:
diff --git a/django_extensions/management/modelviz.py b/django_extensions/management/modelviz.py
--- a/django_extensions/management/modelviz.py
+++ b/django_extensions/management/modelviz.py
@@ -17,6 +17,7 @@
     ForeignKey, ManyToManyField, OneToOneField, RelatedField,
 )
 from django.template import Context, Template, loader
+from django.utils.encoding import force_bytes
 from django.utils.safestring import mark_safe
 from django.utils.translation import activate as activate_language
 
@@ -42,6 +43,7 @@
     "Alexander Houben <alexander@houben.ch>",
     "Joern Hees <gitdev@joernhees.de>",
     "Kevin Cherepski <cherepski@gmail.com>",
+    "Jose Tomas Tocino <theom3ga@gmail.com>"
 ]
 
 
@@ -138,14 +140,14 @@ def consider(model_name):
                 continue
 
             if verbose_names and appmodel._meta.verbose_name:
-                model['label'] = appmodel._meta.verbose_name.decode("utf8")
+                model['label'] = force_bytes(appmodel._meta.verbose_name)
             else:
                 model['label'] = model['name']
 
             # model attributes
             def add_attributes(field):
                 if verbose_names and field.verbose_name:
-                    label = field.verbose_name.decode("utf8")
+                    label = force_bytes(field.verbose_name)
                     if label.islower():
                         label = label.capitalize()
                 else:


Test patch: