Marcos Dumay de Medeiros 8 年之前
父節點
當前提交
528d549ec3
共有 12 個文件被更改,包括 482 次插入405 次删除
  1. 326 307
      src/rapid/filters.py
  2. 8 5
      src/rapid/forms.py
  3. 21 15
      src/rapid/models.py
  4. 11 3
      src/rapid/permissions.py
  5. 5 0
      src/rapid/rapidfields.py
  6. 18 12
      src/rapid/rapidforms.py
  7. 9 6
      src/rapid/register.py
  8. 29 22
      src/rapid/registry.py
  9. 7 5
      src/rapid/urls.py
  10. 8 0
      src/rapid/views.py
  11. 17 11
      src/rapid/widgets.py
  12. 23 19
      src/rapid/wrappers.py

+ 326 - 307
src/rapid/filters.py

@@ -1,307 +1,326 @@
-# -*- coding: utf-8 -*-
-
-__author__ = 'marcos.medeiros'
-
-from django.db import models
-from django.db.models.fields.related import ForeignObjectRel
-import datetime
-import decimal
-import inspect
-import locale
-
-from django.template import loader, Context
-
-_filter_templates = 'rapid/filters/'
-_filter_url_parameter = 'filter'
-
-class FilterOperator:
-    def __init__(self, display, query, multiple=False):
-        self.display = display
-        self.query = query
-        self.multiple = multiple
-
-
-class FilterValue:
-    available_operations = []
-    selection_template = _filter_templates + 'key_value.html'
-
-    def __init__(self, field, url_value=''):
-        self.value = None
-        self.field = field
-        raise NotImplementedError
-
-    def query_value(self):
-        return self.value
-
-    def url_value(self):
-        return unicode(self.value)
-
-    def operator_from_url(self, url_value):
-        for o in self.available_operations:
-            if unicode(o.query) == unicode(url_value):
-                return o
-        return None
-
-
-class IntegralFilter(FilterValue):
-    available_operations = [
-        FilterOperator('igual a', 'exact'),
-        FilterOperator('maior que', 'gt'),
-        FilterOperator('maior ou igual a', 'gte'),
-        FilterOperator('menor que', 'lt'),
-        FilterOperator('menor ou igual a', 'lte'),
-    ]
-
-    def __init__(self, field, url_value=0):
-        self.value = int(url_value)
-
-
-class BooleanFilter(FilterValue):
-    available_operations = [
-        FilterOperator('valor', 'exact'),
-    ]
-
-    def __init__(self, field, url_value='true'):
-        self.value = bool(url_value)
-
-    def __unicode__(self):
-        return 'true' if self.value else ''
-
-
-class TextFilter(FilterValue):
-    available_operations = [
-        FilterOperator('igual a', 'iexact'),
-        FilterOperator(u'começa com', 'istartswith'),
-        FilterOperator('acaba com', 'iendswith'),
-        FilterOperator('contém', 'icontains'),
-    ]
-
-    def __init__(self, field, url_value=''):
-        self.value = url_value
-
-    def url_value(self):
-        return self.value if self.value else ''
-
-
-class DateTimeFilter(FilterValue):
-    selection_template = _filter_templates + 'date_value.html'
-    available_operations = [
-        FilterOperator('igual a', 'exact'),
-        FilterOperator('maior que', 'gt'),
-        FilterOperator('maior ou igual a', 'gte'),
-        FilterOperator('menor que', 'lt'),
-        FilterOperator('menor ou igual a', 'lte'),
-    ]
-
-    dateformat = '%Y:%m:%d:%H:%M:%S'
-
-    def __init__(self, field, url_value=None):
-        if url_value:
-            self.value = datetime.datetime.strptime(url_value, self.dateformat)
-        else:
-            self.value = datetime.datetime.now()
-
-    def url_value(self):
-        return self.value.strftime(self.dateformat)
-
-
-class RealFilter(FilterValue):
-    available_operations = [
-        FilterOperator('igual a', 'exact'),
-        FilterOperator('maior que', 'gt'),
-        FilterOperator('maior ou igual a', 'gte'),
-        FilterOperator('menor que', 'lt'),
-        FilterOperator('menor ou igual a', 'lte'),
-    ]
-
-    def __init__(self, field, url_value=0.0):
-        self.value = decimal.Decimal(url_value)
-
-
-class TimeFilter(DateTimeFilter):
-    available_operations = [
-        FilterOperator('igual a', 'exact'),
-        FilterOperator('maior que', 'gt'),
-        FilterOperator('maior ou igual a', 'gte'),
-        FilterOperator('menor que', 'lt'),
-        FilterOperator('menor ou igual a', 'lte'),
-    ]
-
-    dateformat = 'HH:MM:SS'
-
-
-class RelationFilter(FilterValue):
-    available_operations = [
-        FilterOperator('igual a', 'exact'),
-        FilterOperator('na lista', 'in'),
-    ]
-
-    def __init__(self, field, url_value=''):
-        model = field.related_model()
-        self.model = model
-        self.value = [model.default_manager().filter(pk__in=int(v)) for v in url_value.split(':') if v]
-
-    def url_value(self):
-        return ':'.join([str(v.pk) for v in self.value])
-
-
-field_type_dispatcher = {
-    models.AutoField: IntegralFilter,
-    models.BigIntegerField: IntegralFilter,
-    #models.BinaryField:
-    #models.BooleanField: BooleanFilter,
-    models.CharField: TextFilter,
-    #models.CommaSeparatedIntegerField:
-    #models.DateField: DateTimeFilter,
-    #models.DateTimeField: DateTimeFilter,
-    #models.DecimalField: RealFilter,
-    #models.DurationField:TimeFilter,
-    models.EmailField: TextFilter,
-    #models.FileField:
-    #models.FilePathField:
-    models.FloatField: RealFilter,
-    #models.ImageField:
-    models.IntegerField: IntegralFilter,
-    #models.IPAddressField:
-    #models.GenericIPAddressField:
-    #models.NullBooleanField: BooleanFilter,
-    models.PositiveIntegerField: IntegralFilter,
-    models.PositiveSmallIntegerField: IntegralFilter,
-    #models.SlugField:
-    models.SmallIntegerField: IntegralFilter,
-    models.TextField: TextFilter,
-    #models.TimeField: TimeFilter,
-    #models.URLField:
-    #models.UUIDField:
-    #models.ForeignKey: RelationFilter,
-    #models.ManyToManyField: RelationFilter,
-    #models.OneToOneField: RelationFilter,
-    #models.Manager: RelationFilter,
-    #ForeignObjectRel: RelationFilter,
-}
-
-def _get_field_type(field):
-    tt = inspect.getmro(type(field.field))
-    for t in tt:
-        v = field_type_dispatcher.get(t)
-        if v:
-            return v
-    return None
-
-def _get_default_field_value(field):
-    t = _get_field_type(field)
-    if t:
-        return t(field)
-    return None
-
-def _get_field_value(field, url_value):
-    value_type = _get_field_type(field)
-    if value_type:
-        return value_type(field, url_value)
-    return None
-
-class Filter:
-    def __init__(self, field, operator=None, value=None):
-        self.field = field
-        if value:
-            self.value = value
-        else:
-            self.value = _get_default_field_value(field)
-        if operator:
-            self.operator = operator
-        else:
-            self.operator = self.value.available_operations[0]
-
-    def query_dict(self):
-        return self.field.bare_name() + '__' + self.operator.query, self.value.query_value()
-
-    def url_para(self):
-        return self.field.bare_name() + '-' + self.operator.query + '=' + self.value.url_vaue()
-
-    @classmethod
-    def from_request(cls, field, request):
-        for o in _get_field_type(field).available_operations:
-            if request.GET.has_key(field.bare_name() + "-" + o.query):
-                valstr = request.GET[field.bare_name() + "-" + o.query]
-                val = _get_field_value(field, valstr)
-                yield Filter(field, o, val)
-
-    def selection_value_html(self, request):
-        c = Context({
-            'id': self.field.bare_name() + '_' + self.operator.query,
-            'field': self.field,
-            'operator': self.operator,
-            'default_value': self.value.value,
-        })
-        t = loader.get_template(self.value.selection_template)
-        return t.render(c, request)
-
-    @classmethod
-    def selection_type_html(cls, field, request):
-        v = _get_field_type(field)
-        ff = [Filter(field, o) for o in v.available_operations]
-        ss = [(f.operator, f.selection_value_html(request)) for f in ff]
-        act = request.get_full_path()
-        c = Context({
-            'field': field,
-            'operators': v.available_operations,
-            'selectors': ss,
-            'action': act,
-        })
-        t = loader.get_template(_filter_templates + 'column_selector.html')
-        return t.render(c)
-
-
-class FilterSet:
-    def __init__(self, filters=None):
-        self.filters = filters if filters else {}
-
-    def query_dict(self):
-        q = []
-        for ff in self.filters.values():
-            q += [f.query_dict() for f in ff]
-        return dict(q)
-
-    def url_para(self):
-        return ';'.join([f.url_para for f in self.filters])
-
-    @classmethod
-    def from_request(cls, model, request):
-        ff = dict([(f, list(Filter.from_request(f, request))) for f in model.fields() if _get_field_type(f)])
-        return FilterSet(ff)
-
-    @classmethod
-    def can_filter(cls, field):
-        return bool(_get_field_type(field))
-
-    def render_filters(self, request):
-        remove_filter_element = '<a class="rapid-remove-filter"><span class="fa fa-times"></span></a>'
-        ret = ''
-        kk = self.filters.keys()
-        kk.sort(key=lambda f: f.name(), cmp=locale.strcoll)
-        for field in kk:
-            ret += '<div class="rapid-field-filters %s %s">%s\n' % ('visible' if self.filters[field] else 'hidden',
-                                                                    field.bare_name(), field.name().capitalize())
-            for f in self.filters[field]:
-                ret += '<div>' + f.selection_value_html(request) + remove_filter_element + '</div>\n'
-            ret += '</div>'
-        return ret
-
-    def render_selectors(self, request):
-        ret = ''
-        kk = self.filters.keys()
-        kk.sort(key=lambda f: f.name(), cmp=locale.strcoll)
-        for field in kk:
-            ret += '<div class="rapid-filter-selection %s hidden">\n' % field.bare_name()
-            ret += Filter.selection_type_html(field, request)
-            ret += '</div>\n'
-        return ret
-
-    def filters_url(self):
-        pass
-
-    def has_filters(self):
-        for k in self.filters.keys():
-            if self.filters[k]:
-                return True
-        return False
+# -*- coding: utf-8 -*-
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
+from django.db import models
+# noinspection PyUnresolvedReferences
+import datetime
+import decimal
+import inspect
+from django.utils.encoding import force_text
+import locale
+
+from django.template import loader, Context
+
+_filter_templates = 'rapid/filters/'
+_filter_url_parameter = 'filter'
+
+
+class FilterOperator(object):
+    def __init__(self, display, query, multiple=False):
+        self.display = display
+        self.query = query
+        self.multiple = multiple
+
+
+class FilterValue(object):
+    available_operations = []
+    selection_template = _filter_templates + 'key_value.html'
+
+    # noinspection PyUnusedLocal
+    def __init__(self, field, url_value=''):
+        self.value = None
+        self.field = field
+        raise NotImplementedError
+
+    def query_value(self):
+        return self.value
+
+    def url_value(self):
+        return force_text(self.value)
+
+    def operator_from_url(self, url_value):
+        for o in self.available_operations:
+            if force_text(o.query) == url_value:
+                return o
+        return None
+
+
+class IntegralFilter(FilterValue):
+    available_operations = [
+        FilterOperator('igual a', 'exact'),
+        FilterOperator('maior que', 'gt'),
+        FilterOperator('maior ou igual a', 'gte'),
+        FilterOperator('menor que', 'lt'),
+        FilterOperator('menor ou igual a', 'lte'),
+    ]
+
+    # noinspection PyMissingConstructor,PyUnusedLocal
+    def __init__(self, field, url_value=0):
+        self.value = int(url_value)
+
+
+class BooleanFilter(FilterValue):
+    available_operations = [
+        FilterOperator('valor', 'exact'),
+    ]
+
+    # noinspection PyMissingConstructor,PyUnusedLocal
+    def __init__(self, field, url_value='true'):
+        self.value = bool(url_value)
+
+    def __unicode__(self):
+        return 'true' if self.value else ''
+
+
+class TextFilter(FilterValue):
+    available_operations = [
+        FilterOperator('igual a', 'iexact'),
+        FilterOperator('começa com', 'istartswith'),
+        FilterOperator('acaba com', 'iendswith'),
+        FilterOperator('contém', 'icontains'),
+    ]
+
+    # noinspection PyMissingConstructor,PyUnusedLocal
+    def __init__(self, field, url_value=''):
+        self.value = url_value
+
+    def url_value(self):
+        return self.value if self.value else ''
+
+
+class DateTimeFilter(FilterValue):
+    selection_template = _filter_templates + 'date_value.html'
+    available_operations = [
+        FilterOperator('igual a', 'exact'),
+        FilterOperator('maior que', 'gt'),
+        FilterOperator('maior ou igual a', 'gte'),
+        FilterOperator('menor que', 'lt'),
+        FilterOperator('menor ou igual a', 'lte'),
+    ]
+
+    date_format = '%Y:%m:%d:%H:%M:%S'
+
+    # noinspection PyMissingConstructor,PyUnusedLocal
+    def __init__(self, field, url_value=None):
+        if url_value:
+            self.value = datetime.datetime.strptime(url_value, self.date_format)
+        else:
+            self.value = datetime.datetime.now()
+
+    def url_value(self):
+        return self.value.strftime(self.date_format)
+
+
+class RealFilter(FilterValue):
+    available_operations = [
+        FilterOperator('igual a', 'exact'),
+        FilterOperator('maior que', 'gt'),
+        FilterOperator('maior ou igual a', 'gte'),
+        FilterOperator('menor que', 'lt'),
+        FilterOperator('menor ou igual a', 'lte'),
+    ]
+
+    # noinspection PyMissingConstructor,PyUnusedLocal
+    def __init__(self, field, url_value=0.0):
+        self.value = decimal.Decimal(url_value)
+
+
+class TimeFilter(DateTimeFilter):
+    available_operations = [
+        FilterOperator('igual a', 'exact'),
+        FilterOperator('maior que', 'gt'),
+        FilterOperator('maior ou igual a', 'gte'),
+        FilterOperator('menor que', 'lt'),
+        FilterOperator('menor ou igual a', 'lte'),
+    ]
+
+    date_format = 'HH:MM:SS'
+
+
+class RelationFilter(FilterValue):
+    available_operations = [
+        FilterOperator('igual a', 'exact'),
+        FilterOperator('na lista', 'in'),
+    ]
+
+    # noinspection PyMissingConstructor
+    def __init__(self, field, url_value=''):
+        model = field.related_model()
+        self.model = model
+        self.value = [model.default_manager().filter(pk__in=int(v)) for v in url_value.split(':') if v]
+
+    def url_value(self):
+        return ':'.join([str(v.pk) for v in self.value])
+
+
+field_type_dispatcher = {
+    models.AutoField: IntegralFilter,
+    models.BigIntegerField: IntegralFilter,
+    # models.BinaryField:
+    # models.BooleanField: BooleanFilter,
+    models.CharField: TextFilter,
+    # models.CommaSeparatedIntegerField:
+    # models.DateField: DateTimeFilter,
+    # models.DateTimeField: DateTimeFilter,
+    # models.DecimalField: RealFilter,
+    # models.DurationField:TimeFilter,
+    models.EmailField: TextFilter,
+    # models.FileField:
+    # models.FilePathField:
+    models.FloatField: RealFilter,
+    # models.ImageField:
+    models.IntegerField: IntegralFilter,
+    # models.IPAddressField:
+    # models.GenericIPAddressField:
+    # models.NullBooleanField: BooleanFilter,
+    models.PositiveIntegerField: IntegralFilter,
+    models.PositiveSmallIntegerField: IntegralFilter,
+    # models.SlugField:
+    models.SmallIntegerField: IntegralFilter,
+    models.TextField: TextFilter,
+    # models.TimeField: TimeFilter,
+    # models.URLField:
+    # models.UUIDField:
+    # models.ForeignKey: RelationFilter,
+    # models.ManyToManyField: RelationFilter,
+    # models.OneToOneField: RelationFilter,
+    # models.Manager: RelationFilter,
+    # ForeignObjectRel: RelationFilter,
+}
+
+
+def _get_field_type(field):
+    tt = inspect.getmro(type(field.field))
+    for t in tt:
+        v = field_type_dispatcher.get(t)
+        if v:
+            return v
+    return None
+
+
+def _get_default_field_value(field):
+    t = _get_field_type(field)
+    if t:
+        return t(field)
+    return None
+
+
+def _get_field_value(field, url_value):
+    value_type = _get_field_type(field)
+    if value_type:
+        return value_type(field, url_value)
+    return None
+
+
+class Filter(object):
+    def __init__(self, field, operator=None, value=None):
+        self.field = field
+        if value:
+            self.value = value
+        else:
+            self.value = _get_default_field_value(field)
+        if operator:
+            self.operator = operator
+        else:
+            self.operator = self.value.available_operations[0]
+
+    def query_dict(self):
+        return self.field.bare_name() + '__' + self.operator.query, self.value.query_value()
+
+    def url_para(self):
+        return self.field.bare_name() + '-' + self.operator.query + '=' + self.value.url_vaue()
+
+    @classmethod
+    def from_request(cls, field, request):
+        for o in _get_field_type(field).available_operations:
+            k = field.bare_name() + "-" + o.query
+            if k in request.GET:
+                val_str = request.GET[k]
+                val = _get_field_value(field, val_str)
+                yield Filter(field, o, val)
+
+    def selection_value_html(self, request):
+        c = Context({
+            'id': self.field.bare_name() + '_' + self.operator.query,
+            'field': self.field,
+            'operator': self.operator,
+            'default_value': self.value.value,
+        })
+        t = loader.get_template(self.value.selection_template)
+        return t.render(c, request)
+
+    @classmethod
+    def selection_type_html(cls, field, request):
+        v = _get_field_type(field)
+        ff = [Filter(field, o) for o in v.available_operations]
+        ss = [(f.operator, f.selection_value_html(request)) for f in ff]
+        act = request.get_full_path()
+        c = Context({
+            'field': field,
+            'operators': v.available_operations,
+            'selectors': ss,
+            'action': act,
+        })
+        t = loader.get_template(_filter_templates + 'column_selector.html')
+        return t.render(c)
+
+
+class FilterSet(object):
+    def __init__(self, filters=None):
+        self.filters = filters if filters else {}
+
+    def query_dict(self):
+        q = []
+        for ff in self.filters.values():
+            q += [f.query_dict() for f in ff]
+        return dict(q)
+
+    def url_para(self):
+        return ';'.join([f.url_para for f in self.filters])
+
+    @classmethod
+    def from_request(cls, model, request):
+        ff = dict([(f, list(Filter.from_request(f, request))) for f in model.fields() if _get_field_type(f)])
+        return FilterSet(ff)
+
+    @classmethod
+    def can_filter(cls, field):
+        return bool(_get_field_type(field))
+
+    def render_filters(self, request):
+        remove_filter_element = '<a class="rapid-remove-filter"><span class="fa fa-times"></span></a>'
+        ret = ''
+        kk = self.filters.keys()
+        # noinspection PyTypeChecker
+        kk.sort(key=lambda fd: fd.name(), cmp=locale.strcoll)
+        for field in kk:
+            ret += '<div class="rapid-field-filters %s %s">%s\n' % ('visible' if self.filters[field] else 'hidden',
+                                                                    field.bare_name(), field.name().capitalize())
+            for f in self.filters[field]:
+                ret += '<div>' + f.selection_value_html(request) + remove_filter_element + '</div>\n'
+            ret += '</div>'
+        return ret
+
+    def render_selectors(self, request):
+        ret = ''
+        kk = self.filters.keys()
+        # noinspection PyTypeChecker
+        kk.sort(key=lambda f: f.name(), cmp=locale.strcoll)
+        for field in kk:
+            ret += '<div class="rapid-filter-selection %s hidden">\n' % field.bare_name()
+            ret += Filter.selection_type_html(field, request)
+            ret += '</div>\n'
+        return ret
+
+    def filters_url(self):
+        pass
+
+    def has_filters(self):
+        for k in self.filters.keys():
+            if self.filters[k]:
+                return True
+        return False

+ 8 - 5
src/rapid/forms.py

@@ -1,17 +1,20 @@
 # -*- coding: utf-8 -*-
 # -*- coding: utf-8 -*-
-from django.contrib.contenttypes.models import ContentType
 
 
-__author__ = 'marcos.medeiros'
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
 
 
+from django.contrib.contenttypes.models import ContentType
 from django import forms
 from django import forms
 
 
 from rapid.models import Profile, Application, DocumentTemplate
 from rapid.models import Profile, Application, DocumentTemplate
 from rapid.wrappers import FieldData
 from rapid.wrappers import FieldData
-from rapid.widgets import RapidReadOnly, RapidRelationReadOnly, RapidSelector, rapidAlternativesWidget
+from rapid.widgets import RapidReadOnly, RapidRelationReadOnly, RapidSelector
 
 
 
 
 class ManageUsers(forms.ModelForm):
 class ManageUsers(forms.ModelForm):
-    class Meta:
+    class Meta(object):
         model = Profile
         model = Profile
         fields = '__all__'
         fields = '__all__'
         widgets = {
         widgets = {
@@ -22,7 +25,7 @@ class ManageUsers(forms.ModelForm):
         }
         }
 
 
 
 
-def getDocumentTemplateForm(model):
+def get_document_template_form(model):
     class AddDocumentTemplate(forms.ModelForm):
     class AddDocumentTemplate(forms.ModelForm):
         def save(self, commit=True):
         def save(self, commit=True):
             obj = super(AddDocumentTemplate, self).save(commit=False)
             obj = super(AddDocumentTemplate, self).save(commit=False)

+ 21 - 15
src/rapid/models.py

@@ -1,4 +1,10 @@
 # -*- coding: utf-8 -*-
 # -*- coding: utf-8 -*-
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes.models import ContentType
 
 
 from django.db import models
 from django.db import models
@@ -6,10 +12,10 @@ from django.contrib.auth.models import User
 
 
 
 
 class Application(models.Model):
 class Application(models.Model):
-    name = models.CharField(max_length=60, unique=True, verbose_name=u"nome")
-    python_name = models.CharField(max_length=255, unique=True, verbose_name=u"Nome no Python")
-    managers = models.ManyToManyField(User, verbose_name=u'gestores', related_name='managed_applications')
-    enabled = models.BooleanField(default=True, verbose_name=u"ativa")
+    name = models.CharField(max_length=60, unique=True, verbose_name="nome")
+    python_name = models.CharField(max_length=255, unique=True, verbose_name="Nome no Python")
+    managers = models.ManyToManyField(User, verbose_name='gestores', related_name='managed_applications')
+    enabled = models.BooleanField(default=True, verbose_name="ativa")
 
 
     def __unicode__(self):
     def __unicode__(self):
         return self.name
         return self.name
@@ -17,28 +23,28 @@ class Application(models.Model):
     url_name = 'aplicacao'
     url_name = 'aplicacao'
 
 
     class Meta(object):
     class Meta(object):
-        verbose_name = u'aplicação'
-        verbose_name_plural = u'aplicações'
+        verbose_name = 'aplicação'
+        verbose_name_plural = 'aplicações'
 
 
 
 
 class Profile(models.Model):
 class Profile(models.Model):
     id = models.AutoField(primary_key=True)
     id = models.AutoField(primary_key=True)
-    application = models.ForeignKey(Application, verbose_name=u'aplicação')
-    name = models.CharField(max_length=60, verbose_name=u'nome')
-    description = models.TextField(verbose_name=u'descrição')
-    users = models.ManyToManyField(User, verbose_name=u'usuários', blank=True)
+    application = models.ForeignKey(Application, verbose_name='aplicação')
+    name = models.CharField(max_length=60, verbose_name='nome')
+    description = models.TextField(verbose_name='descrição')
+    users = models.ManyToManyField(User, verbose_name='usuários', blank=True)
 
 
     def __unicode__(self):
     def __unicode__(self):
         return self.name
         return self.name
 
 
     class Meta(object):
     class Meta(object):
-        verbose_name = u'perfil'
-        verbose_name_plural = u'perfis'
+        verbose_name = 'perfil'
+        verbose_name_plural = 'perfis'
         unique_together = (('application', 'name'),)
         unique_together = (('application', 'name'),)
 
 
 
 
 class DocumentTemplate(models.Model):
 class DocumentTemplate(models.Model):
-    name = models.CharField(max_length=60, verbose_name=u'nome')
+    name = models.CharField(max_length=60, verbose_name='nome')
     model = models.ForeignKey(ContentType)
     model = models.ForeignKey(ContentType)
     template = models.FileField(upload_to='rapid/document_templates')
     template = models.FileField(upload_to='rapid/document_templates')
 
 
@@ -46,5 +52,5 @@ class DocumentTemplate(models.Model):
         return self.name
         return self.name
 
 
     class Meta(object):
     class Meta(object):
-        verbose_name = u'template de documento'
-        verbose_name_plural = u'templates de documento'
+        verbose_name = 'template de documento'
+        verbose_name_plural = 'templates de documento'

+ 11 - 3
src/rapid/permissions.py

@@ -1,9 +1,16 @@
 # coding=utf-8
 # coding=utf-8
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
 from django.core.exceptions import ObjectDoesNotExist
 from django.core.exceptions import ObjectDoesNotExist
 from rapid.models import Application, Profile
 from rapid.models import Application, Profile
 
 
 __author__ = 'marcos.medeiros'
 __author__ = 'marcos.medeiros'
 
 
+# noinspection PyProtectedMember
 from registry import _caller_urls_module
 from registry import _caller_urls_module
 
 
 
 
@@ -64,11 +71,12 @@ def has_instance(model, perm, instance):
 def to_profile(profile_name):
 def to_profile(profile_name):
     """
     """
     Grants permission over the model and all instances to the given profile(s)
     Grants permission over the model and all instances to the given profile(s)
+    of the application the model is being registered.
     :param profile_name: Name or list of names of profiles that'll receive the permission.
     :param profile_name: Name or list of names of profiles that'll receive the permission.
     """
     """
     app = Application.objects.get(python_name=_caller_urls_module())  # Should never fail
     app = Application.objects.get(python_name=_caller_urls_module())  # Should never fail
     if hasattr(profile_name, "__iter__"):
     if hasattr(profile_name, "__iter__"):
-        profiles = [p.pk for p in Profile.objects.filter(name__in=profile_name, application=app).all()]
+        profiles = [pf.pk for pf in Profile.objects.filter(name__in=profile_name, application=app).all()]
 
 
         def m(request):
         def m(request):
             if not request.user.is_authenticated():
             if not request.user.is_authenticated():
@@ -131,9 +139,9 @@ def to_superusers():
 def to_application_managers(python_name):
 def to_application_managers(python_name):
     """
     """
     Grants permission over the model and all instances to the manager of the given application
     Grants permission over the model and all instances to the manager of the given application
-    :param app: Application.id of the desired application
+    :param python_name: Name of the desired application main module
     """
     """
-    app = [a.pk for a in Application.objects.filter(python_name=python_name).all()]
+    app = [ap.pk for ap in Application.objects.filter(python_name=python_name).all()]
 
 
     def m(request):
     def m(request):
         if not request.user.is_authenticated():
         if not request.user.is_authenticated():

+ 5 - 0
src/rapid/rapidfields.py

@@ -1,5 +1,10 @@
 # coding=utf-8
 # coding=utf-8
 
 
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
 from django.contrib.contenttypes.fields import GenericForeignKey
 from django.contrib.contenttypes.fields import GenericForeignKey
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes.models import ContentType
 from rapid.rapidforms import RapidAlternativesField
 from rapid.rapidforms import RapidAlternativesField

+ 18 - 12
src/rapid/rapidforms.py

@@ -1,10 +1,16 @@
 # coding=utf-8
 # coding=utf-8
 
 
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes.models import ContentType
 from django.core.exceptions import ValidationError
 from django.core.exceptions import ValidationError
 from django.db import transaction
 from django.db import transaction
 
 
 import gettext
 import gettext
+from django.utils.encoding import force_text
 
 
 _ = gettext.gettext
 _ = gettext.gettext
 
 
@@ -14,7 +20,7 @@ import collections
 
 
 from django import forms
 from django import forms
 
 
-from rapid.widgets import RapidSelector, RapidRelationReadOnly, rapidAlternativesWidget
+from rapid.widgets import RapidSelector, RapidRelationReadOnly, rapid_alternatives_widget
 from rapid.wrappers import FieldData, ModelData
 from rapid.wrappers import FieldData, ModelData
 
 
 
 
@@ -38,7 +44,7 @@ class RapidAlternativesField(forms.Field):
                 fm = ft(prefix=prefix, instance=inst)
                 fm = ft(prefix=prefix, instance=inst)
             alt.append((md.content_type().pk, (md, fm, selected)))
             alt.append((md.content_type().pk, (md, fm, selected)))
         alt = dict(alt)
         alt = dict(alt)
-        kwargs['widget'] = rapidAlternativesWidget(alt, selector_name)
+        kwargs['widget'] = rapid_alternatives_widget(alt, selector_name)
         # noinspection PyArgumentList
         # noinspection PyArgumentList
         super(RapidAlternativesField, self).__init__(field_name, *args, **kwargs)
         super(RapidAlternativesField, self).__init__(field_name, *args, **kwargs)
 
 
@@ -65,7 +71,7 @@ def for_model(request, model, default_relations=()):
             f = FieldData(getattr(model, x).field, request)
             f = FieldData(getattr(model, x).field, request)
             widgets.append((x, RapidRelationReadOnly(f.related_model())))
             widgets.append((x, RapidRelationReadOnly(f.related_model())))
     for f in ModelData(model).local_fields():
     for f in ModelData(model).local_fields():
-        if f.is_relation() and unicode(f.bare_name()) not in default_relations_fields:
+        if f.is_relation() and force_text(f.bare_name()) not in default_relations_fields:
             if f.related_model().has_permission(request, 'select'):
             if f.related_model().has_permission(request, 'select'):
                 widgets.append((f.bare_name(), RapidSelector(f)))
                 widgets.append((f.bare_name(), RapidSelector(f)))
     # ModelForm.Meta has attributes with the same names, thus I'll rename them
     # ModelForm.Meta has attributes with the same names, thus I'll rename them
@@ -81,15 +87,15 @@ def for_model(request, model, default_relations=()):
             if initial:
             if initial:
                 kwargs['initial'] = initial
                 kwargs['initial'] = initial
             instance = kwargs.get('instance')
             instance = kwargs.get('instance')
-            for n, f in ModelData(model).rapid_alternative_data():
-                ct = ModelData(model).field_by_name(f.ct_field).field
-                fk = ModelData(model).field_by_name(f.fk_field).field
+            for n, fd in ModelData(model).rapid_alternative_data():
+                ct = ModelData(model).field_by_name(fd.ct_field).field
+                fk = ModelData(model).field_by_name(fd.fk_field).field
                 # noinspection PyTypeChecker
                 # noinspection PyTypeChecker
                 fl = RapidAlternativesField(n, ct.alternatives, ct.name, self, request, instance)
                 fl = RapidAlternativesField(n, ct.alternatives, ct.name, self, request, instance)
                 # noinspection PyArgumentList
                 # noinspection PyArgumentList
                 type(self.__class__).__setattr__(self.__class__, n, fl)
                 type(self.__class__).__setattr__(self.__class__, n, fl)
                 nd = collections.OrderedDict()
                 nd = collections.OrderedDict()
-                for k, v in self.__class__.base_fields.iteritems():
+                for k, v in self.__class__.base_fields.items():
                     if k == fk.name:
                     if k == fk.name:
                         nd[n] = fl
                         nd[n] = fl
                     else:
                     else:
@@ -103,17 +109,17 @@ def for_model(request, model, default_relations=()):
                 return super(CForm, self).save(commit)
                 return super(CForm, self).save(commit)
             else:
             else:
                 obj = super(CForm, self).save(commit=False)
                 obj = super(CForm, self).save(commit=False)
-                for n, f in ModelData(model).rapid_alternative_data():
+                for n, fd in ModelData(model).rapid_alternative_data():
                     if self.instance:
                     if self.instance:
-                        old_t = getattr(self.instance, f.ct_field)
-                        new_t = getattr(obj, f.ct_field)
+                        old_t = getattr(self.instance, fd.ct_field)
+                        new_t = getattr(obj, fd.ct_field)
                         if old_t != new_t:
                         if old_t != new_t:
-                            getattr(self.instance, f.bare_name).delete()
+                            getattr(self.instance, fd.bare_name).delete()
                     fob = self.cleaned_data[n]
                     fob = self.cleaned_data[n]
                     fob.save()
                     fob.save()
                     if hasattr(fob, 'save_m2m'):
                     if hasattr(fob, 'save_m2m'):
                         fob.save_m2m()
                         fob.save_m2m()
-                    setattr(obj, f.fk_field, fob.pk)
+                    setattr(obj, fd.fk_field, fob.pk)
                 obj.save()
                 obj.save()
                 self.save_m2m()
                 self.save_m2m()
                 return obj
                 return obj

+ 9 - 6
src/rapid/register.py

@@ -1,9 +1,12 @@
 # coding=utf-8
 # coding=utf-8
 
 
-__author__ = 'marcos'
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
 
 
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes.models import ContentType
-from rapid.forms import getDocumentTemplateForm
+from rapid.forms import get_document_template_form
 from rapid.models import DocumentTemplate
 from rapid.models import DocumentTemplate
 from rapid.views import bare_or_main, ListView, ReadView, UpdateView, CreateView, SelectView, DeleteView,\
 from rapid.views import bare_or_main, ListView, ReadView, UpdateView, CreateView, SelectView, DeleteView,\
     update_form_class, RenderDocumentView, add_form_class, get_delete_document_template_view
     update_form_class, RenderDocumentView, add_form_class, get_delete_document_template_view
@@ -53,6 +56,7 @@ def crud(model, read_set, write_set, actions=None, url_name=None, can_erase=Fals
         ret.append(registry.register_action(a, MenuEntry(model, write_set, url_name=url_name)))
         ret.append(registry.register_action(a, MenuEntry(model, write_set, url_name=url_name)))
     return [u for u in ret if u]
     return [u for u in ret if u]
 
 
+
 # noinspection PyShadowingNames
 # noinspection PyShadowingNames
 def instance_form(model, action_name, entry_name, form, permission_set,
 def instance_form(model, action_name, entry_name, form, permission_set,
                   url_name=None, icon=None, visibility=None):
                   url_name=None, icon=None, visibility=None):
@@ -84,10 +88,9 @@ def custom_action(model, action, permission, url_name=None):
 def document_templates(model, templates_permission, render_permission, url_name=None,
 def document_templates(model, templates_permission, render_permission, url_name=None,
                        render_visibility=Action.Visibility.details):
                        render_visibility=Action.Visibility.details):
     ct_model = ContentType.objects.get_for_model(model)
     ct_model = ContentType.objects.get_for_model(model)
-    template_generator = lambda n: lambda: ((d.name, [(n, d.pk),],) for
-                                  d in DocumentTemplate.objects.filter(model=ct_model))
-    model_class = model  # renamimg because of clash with the next function argument
-    add_act = Action("add-template", "", (), _rvw(add_form_class(getDocumentTemplateForm(model)), 'add-template'),
+    template_generator = lambda n: lambda: ((d.name, [(n, d.pk), ], ) for
+                                            d in DocumentTemplate.objects.filter(model=ct_model))
+    add_act = Action("add-template", "", (), _rvw(add_form_class(get_document_template_form(model)), 'add-template'),
                      "Novo Template", "fa-upload")
                      "Novo Template", "fa-upload")
     del_act = Action("del-template", "(?P<pk>[0-9]+)", (),
     del_act = Action("del-template", "(?P<pk>[0-9]+)", (),
                      _rvw(get_delete_document_template_view(model), 'del-template'), "Excluir Template",
                      _rvw(get_delete_document_template_view(model), 'del-template'), "Excluir Template",

+ 29 - 22
src/rapid/registry.py

@@ -1,11 +1,20 @@
+# coding=utf-8
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
 from django.core.urlresolvers import reverse
 from django.core.urlresolvers import reverse
 from django.db.utils import OperationalError
 from django.db.utils import OperationalError
+from django.utils.encoding import python_2_unicode_compatible
 from rapid.models import Application
 from rapid.models import Application
 from django.conf.urls import url
 from django.conf.urls import url
 import inspect
 import inspect
 import logging
 import logging
 from os import path
 from os import path
 
 
+
 def _split_all_path(file_name):
 def _split_all_path(file_name):
     file_name = path.splitdrive(file_name)[1]
     file_name = path.splitdrive(file_name)[1]
     p = 'a'
     p = 'a'
@@ -13,25 +22,29 @@ def _split_all_path(file_name):
         file_name, p = path.split(file_name)
         file_name, p = path.split(file_name)
         yield p
         yield p
 
 
+
 def _caller_urls_module():
 def _caller_urls_module():
     st = inspect.stack()
     st = inspect.stack()
     for rec in st:
     for rec in st:
         file_name = rec[1]
         file_name = rec[1]
         segments = list(_split_all_path(file_name))
         segments = list(_split_all_path(file_name))
-        i = 0
-        for i in xrange(0, len(segments) - 2):
+        for i in range(0, len(segments) - 2):
             p = path.normcase(segments[i])
             p = path.normcase(segments[i])
             p = path.splitext(p)[0]
             p = path.splitext(p)[0]
             if p == "urls":
             if p == "urls":
                 return segments[i+1]
                 return segments[i+1]
     return None
     return None
 
 
+
 def _model_name(model):
 def _model_name(model):
     if hasattr(model, "url_name"):
     if hasattr(model, "url_name"):
         return model.url_name
         return model.url_name
+    # noinspection PyProtectedMember
     return model._meta.verbose_name
     return model._meta.verbose_name
 
 
-class MenuEntry:
+
+@python_2_unicode_compatible
+class MenuEntry(object):
     """
     """
     The data that goes on a menu item.
     The data that goes on a menu item.
     Model, permissions and url
     Model, permissions and url
@@ -41,6 +54,7 @@ class MenuEntry:
         self.model = model
         self.model = model
         self.permission = permission
         self.permission = permission
 
 
+    # noinspection PyUnresolvedReferences
     def get_url(self, instance=None):
     def get_url(self, instance=None):
         ats = [(x, getattr(instance, x)) for x in self.action.query_parameters]
         ats = [(x, getattr(instance, x)) for x in self.action.query_parameters]
         if self.action.pick_generator:
         if self.action.pick_generator:
@@ -48,14 +62,11 @@ class MenuEntry:
                     n, p in self.action.pick_generator()]
                     n, p in self.action.pick_generator()]
         return reverse(self.url, kwargs=dict(ats))
         return reverse(self.url, kwargs=dict(ats))
 
 
-    def __unicode__(self):
-        return u"Menu entry: " + self.url_name + " -> " + unicode(self.action)
-
     def __str__(self):
     def __str__(self):
-        return str(unicode(self))
+        return "Menu entry: " + self.url_name + " -> " + str(self.action)
 
 
 
 
-class ModuleEntry:
+class ModuleEntry(object):
     """
     """
     Module data used at menu construction
     Module data used at menu construction
     """
     """
@@ -65,7 +76,8 @@ class ModuleEntry:
         self.models = set()
         self.models = set()
 
 
 
 
-class Action:
+@python_2_unicode_compatible
+class Action(object):
     """
     """
     An action to be done over a model.
     An action to be done over a model.
     Default actions are "list", "view", "edit", "add", "delete", and "select",
     Default actions are "list", "view", "edit", "add", "delete", and "select",
@@ -84,11 +96,8 @@ class Action:
         self.pick_generator = pick_generator
         self.pick_generator = pick_generator
         self.overlay = overlay if overlay else self.Overlay.better_in_overlay
         self.overlay = overlay if overlay else self.Overlay.better_in_overlay
 
 
-    def __unicode__(self):
-        return u"Action: " + self.name
-
     def __str__(self):
     def __str__(self):
-        return str(unicode(self))
+        return "Action: " + self.name
 
 
     class Visibility(object):
     class Visibility(object):
         hidden = 1
         hidden = 1
@@ -101,7 +110,7 @@ class Action:
         clear_overlays = 'clear-overlays'
         clear_overlays = 'clear-overlays'
 
 
 
 
-class _Registry:
+class _Registry(object):
     """
     """
     Registry of URLs, models and views present on the menu
     Registry of URLs, models and views present on the menu
 
 
@@ -129,24 +138,23 @@ class _Registry:
                 m = ModuleEntry(a.python_name, a.name)
                 m = ModuleEntry(a.python_name, a.name)
                 self._modules[a.python_name] = m
                 self._modules[a.python_name] = m
         except OperationalError:
         except OperationalError:
-            #Should always get fixed by a migration
+            # Should always get fixed by a migration
             logging.error("Can not query applications table. You may need to run \"manage.py migrate\".")
             logging.error("Can not query applications table. You may need to run \"manage.py migrate\".")
 
 
     def register_action(self, action, entry, **kwargs):
     def register_action(self, action, entry, **kwargs):
         """
         """
         Registers an action at this registry, so it will appear on the menu
         Registers an action at this registry, so it will appear on the menu
-        and can be reversed at the cruds.
+        and can be reversed at the CRUDs.
         :param action: Action type
         :param action: Action type
         :param entry: The menu entry where it will appear
         :param entry: The menu entry where it will appear
         :param kwargs: Arguments (besides model) that'll be passed to the view_factory of the action
         :param kwargs: Arguments (besides model) that'll be passed to the view_factory of the action
         :return: A Django URL pattern that should be added to the patterns of a urls.py module
         :return: A Django URL pattern that should be added to the patterns of a urls.py module
         """
         """
-        from django.contrib.auth.models import User
         module_name = _caller_urls_module()
         module_name = _caller_urls_module()
         model = entry.model
         model = entry.model
         if not module_name:
         if not module_name:
             raise Exception("Unidentified python module registering " + str(model))
             raise Exception("Unidentified python module registering " + str(model))
-        if not registry._modules.has_key(module_name):
+        if module_name not in registry._modules:
             if Application.objects.filter(python_name=module_name):
             if Application.objects.filter(python_name=module_name):
                 registry._modules[module_name] = Application.objects.get(python_name=module_name)
                 registry._modules[module_name] = Application.objects.get(python_name=module_name)
             else:
             else:
@@ -163,7 +171,7 @@ class _Registry:
         entry_url = module_entry.menu_name + '_' + entry.url_name + '_' + action.name
         entry_url = module_entry.menu_name + '_' + entry.url_name + '_' + action.name
         entry.url = entry_url
         entry.url = entry_url
         model_actions = self._models.get(model, {})
         model_actions = self._models.get(model, {})
-        if model_actions.has_key(action.name):
+        if action.name in model_actions:
             raise Exception("Action " + action.name + " already registered for model " + str(model))
             raise Exception("Action " + action.name + " already registered for model " + str(model))
         model_actions[action.name] = entry
         model_actions[action.name] = entry
         self._models[model] = model_actions
         self._models[model] = model_actions
@@ -172,10 +180,9 @@ class _Registry:
             url_path += '/%s' % action.url_parameters
             url_path += '/%s' % action.url_parameters
         return url(url_path+'/?$', action.view_factory(model=entry.model, **kwargs), name=entry_url)
         return url(url_path+'/?$', action.view_factory(model=entry.model, **kwargs), name=entry_url)
 
 
-
     def get_url_of_action(self, model, action_name, **kwargs):
     def get_url_of_action(self, model, action_name, **kwargs):
         acts = self._models.get(model)
         acts = self._models.get(model)
-        if acts and acts.has_key(action_name):
+        if acts and action_name in acts:
             return reverse(acts[action_name].url, kwargs=kwargs)
             return reverse(acts[action_name].url, kwargs=kwargs)
 
 
     def modules(self):
     def modules(self):
@@ -185,7 +192,7 @@ class _Registry:
         return [x.menu_name for x in self._modules.values()]
         return [x.menu_name for x in self._modules.values()]
 
 
     def is_controlled(self, model):
     def is_controlled(self, model):
-        return self._models.has_key(model)
+        return model in self._models
 
 
     def model_entry(self, model):
     def model_entry(self, model):
         return self._models.get(model)
         return self._models.get(model)

+ 7 - 5
src/rapid/urls.py

@@ -1,6 +1,9 @@
 # -*- coding: utf-8 -*-
 # -*- coding: utf-8 -*-
 
 
-__author__ = 'marcos.medeiros'
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
 
 
 from django.contrib.auth.models import User
 from django.contrib.auth.models import User
 
 
@@ -27,8 +30,7 @@ _manage_users_permission = permissions.Permission(
 
 
 urlpatterns = register.crud(Application, write_set=permissions.to_superusers(), read_set=permissions.to_all()) +\
 urlpatterns = register.crud(Application, write_set=permissions.to_superusers(), read_set=permissions.to_all()) +\
     register.crud(Profile, write_set=permissions.to_superusers(), read_set=permissions.to_staff()) +\
     register.crud(Profile, write_set=permissions.to_superusers(), read_set=permissions.to_staff()) +\
-    register.instance_form(Profile, 'manage_users', u'Gerenciar Usuários',
-                            ManageUsers, _manage_users_permission, icon="fa-users",
-                            visibility=Action.Visibility.list) +\
+    register.instance_form(Profile, 'manage_users', 'Gerenciar Usuários',
+                           ManageUsers, _manage_users_permission, icon="fa-users",
+                           visibility=Action.Visibility.list) +\
     register.select(User, ['username'], permissions.to_staff(), 'usuario')
     register.select(User, ['username'], permissions.to_staff(), 'usuario')
-

+ 8 - 0
src/rapid/views.py

@@ -1,4 +1,10 @@
 # -*- coding: utf-8 -*-
 # -*- coding: utf-8 -*-
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
 from django.conf import settings
 from django.conf import settings
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes.models import ContentType
 
 
@@ -18,6 +24,7 @@ from rapidforms import for_model
 import math
 import math
 from os import path
 from os import path
 
 
+
 def _build_uri(request, params):
 def _build_uri(request, params):
     param_string = "&".join(["%s=%s" % (urlquote_plus(k), urlquote_plus(params[k])) for k in params.keys()])
     param_string = "&".join(["%s=%s" % (urlquote_plus(k), urlquote_plus(params[k])) for k in params.keys()])
     base = request.build_absolute_uri().split("?")[0]
     base = request.build_absolute_uri().split("?")[0]
@@ -443,6 +450,7 @@ class RenderDocumentView(generic.View):
 def get_delete_document_template_view(model):
 def get_delete_document_template_view(model):
     class DeleteDocumentTemplateView(DeleteView):
     class DeleteDocumentTemplateView(DeleteView):
         def get_object(self, queryset=None):
         def get_object(self, queryset=None):
+            # noinspection PyUnresolvedReferences
             return get_object_or_404(DocumentTemplate, pk=self.kwargs['pk'])
             return get_object_or_404(DocumentTemplate, pk=self.kwargs['pk'])
 
 
         def has_permission(self, request, instance):
         def has_permission(self, request, instance):

+ 17 - 11
src/rapid/widgets.py

@@ -1,26 +1,32 @@
 # -*- coding: utf-8 -*-
 # -*- coding: utf-8 -*-
-from django.contrib.contenttypes.models import ContentType
 
 
-__author__ = 'marcos.medeiros'
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
 
 
 from django.forms import widgets
 from django.forms import widgets
 from django.template import loader, Context
 from django.template import loader, Context
+from django.utils.encoding import force_text
 
 
 from rapid.wrappers import ModelData
 from rapid.wrappers import ModelData
 
 
 _templates_root = 'rapid/widgets/'
 _templates_root = 'rapid/widgets/'
 
 
+
 class RapidReadOnly(widgets.Widget):
 class RapidReadOnly(widgets.Widget):
     def render(self, name, value, attrs=None):
     def render(self, name, value, attrs=None):
         hidden = '<input type="hidden" name="%s" value="%s" ' % (name, value)
         hidden = '<input type="hidden" name="%s" value="%s" ' % (name, value)
         for a in attrs.keys():
         for a in attrs.keys():
             hidden += '%s="%s" ' % (a, attrs[a])
             hidden += '%s="%s" ' % (a, attrs[a])
         hidden += '>'
         hidden += '>'
-        return '<span class="data-value">%s</span>%s\n' % (unicode(value), hidden)
+        return '<span class="data-value">%s</span>%s\n' % (force_text(value), hidden)
 
 
     def value_from_datadict(self, data, files, name):
     def value_from_datadict(self, data, files, name):
         return data[name]
         return data[name]
 
 
+
 class RapidRelationReadOnly(widgets.Widget):
 class RapidRelationReadOnly(widgets.Widget):
     def __init__(self, model, *args, **kwargs):
     def __init__(self, model, *args, **kwargs):
         super(RapidRelationReadOnly, self).__init__(*args, **kwargs)
         super(RapidRelationReadOnly, self).__init__(*args, **kwargs)
@@ -32,15 +38,15 @@ class RapidRelationReadOnly(widgets.Widget):
             hidden += '%s="%s" ' % (a, attrs[a])
             hidden += '%s="%s" ' % (a, attrs[a])
         hidden += '>'
         hidden += '>'
         if hasattr(value, '__iter__'):
         if hasattr(value, '__iter__'):
-            objs = self.model.default_manager().filter(pk__in=value)
+            obj = self.model.default_manager().filter(pk__in=value)
             ret = ''
             ret = ''
-            for o in objs:
-                ret += '<span class="data-value multiple">%s</span>\n' % unicode(o)
+            for o in obj:
+                ret += '<span class="data-value multiple">%s</span>\n' % force_text(o)
             ret += hidden
             ret += hidden
             return ret
             return ret
         else:
         else:
             obj = self.model.default_manager().get(pk=value)
             obj = self.model.default_manager().get(pk=value)
-            return '<span class="data-value">%s</span>%s\n' % (unicode(obj), hidden)
+            return '<span class="data-value">%s</span>%s\n' % (force_text(obj), hidden)
 
 
     def value_from_datadict(self, data, files, name):
     def value_from_datadict(self, data, files, name):
         return data[name]
         return data[name]
@@ -61,7 +67,7 @@ class RapidSelector(widgets.Select):
         self.remove_deselected = relation.is_weak()
         self.remove_deselected = relation.is_weak()
 
 
     def render(self, name, value, attrs=None, choices=()):
     def render(self, name, value, attrs=None, choices=()):
-        id = attrs.get('id', name)
+        tp_id = attrs.get('id', name)
         related = self.relation.related_model()
         related = self.relation.related_model()
         if self.allow_multiple_selected:
         if self.allow_multiple_selected:
             if value:
             if value:
@@ -84,8 +90,8 @@ class RapidSelector(widgets.Select):
                 icon = 'fa-trash-o'
                 icon = 'fa-trash-o'
         else:
         else:
             icon = 'fa-search'
             icon = 'fa-search'
-        c = Context({'id': id, 'name': name, 'value': v, 'selected': selected, 'icon': icon, 'select_url': select_url,
-                     'multiple': self.allow_multiple_selected})
+        c = Context({'id': tp_id, 'name': name, 'value': v, 'selected': selected, 'icon': icon,
+                     'select_url': select_url, 'multiple': self.allow_multiple_selected})
         if self.allow_multiple_selected:
         if self.allow_multiple_selected:
             t = loader.get_template(_templates_root + 'multiple-selector.html')
             t = loader.get_template(_templates_root + 'multiple-selector.html')
         else:
         else:
@@ -104,7 +110,7 @@ class RapidSelector(widgets.Select):
             return None
             return None
 
 
 
 
-def rapidAlternativesWidget(alternatives, selector):
+def rapid_alternatives_widget(alternatives, selector):
     class RapidAlternativeFormsWidget(widgets.Widget):
     class RapidAlternativeFormsWidget(widgets.Widget):
         def render(self, name, value, attrs=None):
         def render(self, name, value, attrs=None):
             attrs = attrs if attrs else []
             attrs = attrs if attrs else []

+ 23 - 19
src/rapid/wrappers.py

@@ -1,8 +1,12 @@
 # -*- coding: utf-8 -*-
 # -*- coding: utf-8 -*-
-from django.contrib.contenttypes.fields import GenericForeignKey
-from django.contrib.contenttypes.models import ContentType
 
 
-__author__ = 'marcos.medeiros'
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
+from django.contrib.contenttypes.models import ContentType
+from django.utils.encoding import force_text
 
 
 from rapid.registry import registry, Action
 from rapid.registry import registry, Action
 from rapid import filters
 from rapid import filters
@@ -12,7 +16,7 @@ from django.db import models
 from rapid import permissions
 from rapid import permissions
 
 
 
 
-class InstanceData:
+class InstanceData(object):
     def __init__(self, instance, request=None, excludes=None, creator=None, fields=None):
     def __init__(self, instance, request=None, excludes=None, creator=None, fields=None):
         excludes = [] if excludes is None else excludes
         excludes = [] if excludes is None else excludes
         self.model = ModelData(type(instance), request, excludes, creator, fields)
         self.model = ModelData(type(instance), request, excludes, creator, fields)
@@ -133,13 +137,13 @@ class InstanceData:
         return False
         return False
 
 
     def __unicode__(self):
     def __unicode__(self):
-        return unicode(self.instance)
+        return force_text(self.instance)
 
 
     def __str__(self):
     def __str__(self):
         return str(self.model) + ': ' + str(self.instance.pk)
         return str(self.model) + ': ' + str(self.instance.pk)
 
 
 
 
-class ModelData:
+class ModelData(object):
     def __init__(self, model, request=None, excludes=None, creator=None, fields=None):
     def __init__(self, model, request=None, excludes=None, creator=None, fields=None):
         excludes = [] if excludes is None else excludes
         excludes = [] if excludes is None else excludes
         self.model = model
         self.model = model
@@ -150,11 +154,11 @@ class ModelData:
 
 
     def model_name(self):
     def model_name(self):
         # noinspection PyProtectedMember
         # noinspection PyProtectedMember
-        return unicode(self.model._meta.verbose_name)
+        return force_text(self.model._meta.verbose_name)
 
 
     def model_name_plural(self):
     def model_name_plural(self):
         # noinspection PyProtectedMember
         # noinspection PyProtectedMember
-        return unicode(self.model._meta.verbose_name_plural)
+        return force_text(self.model._meta.verbose_name_plural)
 
 
     def default_manager(self):
     def default_manager(self):
         # noinspection PyProtectedMember
         # noinspection PyProtectedMember
@@ -209,7 +213,7 @@ class ModelData:
 
 
         Those are not returned by fields()
         Those are not returned by fields()
         """
         """
-        for k, v in self.model.__dict__.iteritems():
+        for k, v in self.model.__dict__.items():
             if hasattr(v, 'is_rapid_alternatives') and v.is_rapid_alternatives:
             if hasattr(v, 'is_rapid_alternatives') and v.is_rapid_alternatives:
                 yield (k, v)
                 yield (k, v)
 
 
@@ -270,13 +274,13 @@ class ModelData:
         return ContentType.objects.get_for_model(self.model)
         return ContentType.objects.get_for_model(self.model)
 
 
     def __unicode__(self):
     def __unicode__(self):
-        return unicode(self.model)
+        return force_text(self.model)
 
 
     def __str__(self):
     def __str__(self):
         return 'Model: ' + str(self.model)
         return 'Model: ' + str(self.model)
 
 
 
 
-class FieldData:
+class FieldData(object):
     def __init__(self, field, request=None):
     def __init__(self, field, request=None):
         self.field = field
         self.field = field
         self.request = request
         self.request = request
@@ -285,30 +289,30 @@ class FieldData:
     def from_model(cls, model, field_name):
     def from_model(cls, model, field_name):
         ff = ModelData(model).fields()
         ff = ModelData(model).fields()
         for f in ff:
         for f in ff:
-            if f.bare_name() == unicode(field_name):
+            if f.bare_name() == force_text(field_name):
                 return f
                 return f
         return None
         return None
 
 
     def bare_name(self):
     def bare_name(self):
-        return unicode(self.field.name)
+        return force_text(self.field.name)
 
 
     def accessor_name(self):
     def accessor_name(self):
         if hasattr(self.field, 'get_accessor_name'):
         if hasattr(self.field, 'get_accessor_name'):
-            return unicode(self.field.get_accessor_name())
-        return unicode(self.field.name)
+            return force_text(self.field.get_accessor_name())
+        return force_text(self.field.name)
 
 
     def name(self):
     def name(self):
         if self.is_auto() and self.is_relation():
         if self.is_auto() and self.is_relation():
             return self.related_model().model_name_plural() + u' - ' + self.related_field().name()
             return self.related_model().model_name_plural() + u' - ' + self.related_field().name()
         if hasattr(self.field, "verbose_name"):
         if hasattr(self.field, "verbose_name"):
-            return unicode(self.field.verbose_name)
-        return unicode(self.field.name)
+            return force_text(self.field.verbose_name)
+        return force_text(self.field.name)
 
 
     def name_plural(self):
     def name_plural(self):
         if self.is_auto() and self.is_relation():
         if self.is_auto() and self.is_relation():
             return self.related_model().model_name_plural() + u' - ' + self.related_field().name_plural()
             return self.related_model().model_name_plural() + u' - ' + self.related_field().name_plural()
         if hasattr(self.field, "verbose_name_plural"):
         if hasattr(self.field, "verbose_name_plural"):
-            return unicode(self.field.verbose_name_plural)
+            return force_text(self.field.verbose_name_plural)
         return self.name() + "s"
         return self.name() + "s"
 
 
     def is_relation(self):
     def is_relation(self):
@@ -364,7 +368,7 @@ class FieldData:
         return self.bare_name()
         return self.bare_name()
 
 
 
 
-class ValueData:
+class ValueData(object):
     def __init__(self, value, field):
     def __init__(self, value, field):
         self.value = value
         self.value = value
         self.field = field
         self.field = field