Marcos Dumay de Medeiros преди 9 години
родител
ревизия
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 -*-
-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 rapid.models import Profile, Application, DocumentTemplate
 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 Meta:
+    class Meta(object):
         model = Profile
         fields = '__all__'
         widgets = {
@@ -22,7 +25,7 @@ class ManageUsers(forms.ModelForm):
         }
 
 
-def getDocumentTemplateForm(model):
+def get_document_template_form(model):
     class AddDocumentTemplate(forms.ModelForm):
         def save(self, commit=True):
             obj = super(AddDocumentTemplate, self).save(commit=False)

+ 21 - 15
src/rapid/models.py

@@ -1,4 +1,10 @@
 # -*- 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.db import models
@@ -6,10 +12,10 @@ from django.contrib.auth.models import User
 
 
 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):
         return self.name
@@ -17,28 +23,28 @@ class Application(models.Model):
     url_name = 'aplicacao'
 
     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):
     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):
         return self.name
 
     class Meta(object):
-        verbose_name = u'perfil'
-        verbose_name_plural = u'perfis'
+        verbose_name = 'perfil'
+        verbose_name_plural = 'perfis'
         unique_together = (('application', 'name'),)
 
 
 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)
     template = models.FileField(upload_to='rapid/document_templates')
 
@@ -46,5 +52,5 @@ class DocumentTemplate(models.Model):
         return self.name
 
     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
+
+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 rapid.models import Application, Profile
 
 __author__ = 'marcos.medeiros'
 
+# noinspection PyProtectedMember
 from registry import _caller_urls_module
 
 
@@ -64,11 +71,12 @@ def has_instance(model, perm, instance):
 def to_profile(profile_name):
     """
     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.
     """
     app = Application.objects.get(python_name=_caller_urls_module())  # Should never fail
     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):
             if not request.user.is_authenticated():
@@ -131,9 +139,9 @@ def to_superusers():
 def to_application_managers(python_name):
     """
     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):
         if not request.user.is_authenticated():

+ 5 - 0
src/rapid/rapidfields.py

@@ -1,5 +1,10 @@
 # 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.models import ContentType
 from rapid.rapidforms import RapidAlternativesField

+ 18 - 12
src/rapid/rapidforms.py

@@ -1,10 +1,16 @@
 # 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.core.exceptions import ValidationError
 from django.db import transaction
 
 import gettext
+from django.utils.encoding import force_text
 
 _ = gettext.gettext
 
@@ -14,7 +20,7 @@ import collections
 
 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
 
 
@@ -38,7 +44,7 @@ class RapidAlternativesField(forms.Field):
                 fm = ft(prefix=prefix, instance=inst)
             alt.append((md.content_type().pk, (md, fm, selected)))
         alt = dict(alt)
-        kwargs['widget'] = rapidAlternativesWidget(alt, selector_name)
+        kwargs['widget'] = rapid_alternatives_widget(alt, selector_name)
         # noinspection PyArgumentList
         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)
             widgets.append((x, RapidRelationReadOnly(f.related_model())))
     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'):
                 widgets.append((f.bare_name(), RapidSelector(f)))
     # 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:
                 kwargs['initial'] = initial
             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
                 fl = RapidAlternativesField(n, ct.alternatives, ct.name, self, request, instance)
                 # noinspection PyArgumentList
                 type(self.__class__).__setattr__(self.__class__, n, fl)
                 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:
                         nd[n] = fl
                     else:
@@ -103,17 +109,17 @@ def for_model(request, model, default_relations=()):
                 return super(CForm, self).save(commit)
             else:
                 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:
-                        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:
-                            getattr(self.instance, f.bare_name).delete()
+                            getattr(self.instance, fd.bare_name).delete()
                     fob = self.cleaned_data[n]
                     fob.save()
                     if hasattr(fob, 'save_m2m'):
                         fob.save_m2m()
-                    setattr(obj, f.fk_field, fob.pk)
+                    setattr(obj, fd.fk_field, fob.pk)
                 obj.save()
                 self.save_m2m()
                 return obj

+ 9 - 6
src/rapid/register.py

@@ -1,9 +1,12 @@
 # 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 rapid.forms import getDocumentTemplateForm
+from rapid.forms import get_document_template_form
 from rapid.models import DocumentTemplate
 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
@@ -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)))
     return [u for u in ret if u]
 
+
 # noinspection PyShadowingNames
 def instance_form(model, action_name, entry_name, form, permission_set,
                   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,
                        render_visibility=Action.Visibility.details):
     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")
     del_act = Action("del-template", "(?P<pk>[0-9]+)", (),
                      _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.db.utils import OperationalError
+from django.utils.encoding import python_2_unicode_compatible
 from rapid.models import Application
 from django.conf.urls import url
 import inspect
 import logging
 from os import path
 
+
 def _split_all_path(file_name):
     file_name = path.splitdrive(file_name)[1]
     p = 'a'
@@ -13,25 +22,29 @@ def _split_all_path(file_name):
         file_name, p = path.split(file_name)
         yield p
 
+
 def _caller_urls_module():
     st = inspect.stack()
     for rec in st:
         file_name = rec[1]
         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.splitext(p)[0]
             if p == "urls":
                 return segments[i+1]
     return None
 
+
 def _model_name(model):
     if hasattr(model, "url_name"):
         return model.url_name
+    # noinspection PyProtectedMember
     return model._meta.verbose_name
 
-class MenuEntry:
+
+@python_2_unicode_compatible
+class MenuEntry(object):
     """
     The data that goes on a menu item.
     Model, permissions and url
@@ -41,6 +54,7 @@ class MenuEntry:
         self.model = model
         self.permission = permission
 
+    # noinspection PyUnresolvedReferences
     def get_url(self, instance=None):
         ats = [(x, getattr(instance, x)) for x in self.action.query_parameters]
         if self.action.pick_generator:
@@ -48,14 +62,11 @@ class MenuEntry:
                     n, p in self.action.pick_generator()]
         return reverse(self.url, kwargs=dict(ats))
 
-    def __unicode__(self):
-        return u"Menu entry: " + self.url_name + " -> " + unicode(self.action)
-
     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
     """
@@ -65,7 +76,8 @@ class ModuleEntry:
         self.models = set()
 
 
-class Action:
+@python_2_unicode_compatible
+class Action(object):
     """
     An action to be done over a model.
     Default actions are "list", "view", "edit", "add", "delete", and "select",
@@ -84,11 +96,8 @@ class Action:
         self.pick_generator = pick_generator
         self.overlay = overlay if overlay else self.Overlay.better_in_overlay
 
-    def __unicode__(self):
-        return u"Action: " + self.name
-
     def __str__(self):
-        return str(unicode(self))
+        return "Action: " + self.name
 
     class Visibility(object):
         hidden = 1
@@ -101,7 +110,7 @@ class Action:
         clear_overlays = 'clear-overlays'
 
 
-class _Registry:
+class _Registry(object):
     """
     Registry of URLs, models and views present on the menu
 
@@ -129,24 +138,23 @@ class _Registry:
                 m = ModuleEntry(a.python_name, a.name)
                 self._modules[a.python_name] = m
         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\".")
 
     def register_action(self, action, entry, **kwargs):
         """
         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 entry: The menu entry where it will appear
         :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
         """
-        from django.contrib.auth.models import User
         module_name = _caller_urls_module()
         model = entry.model
         if not module_name:
             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):
                 registry._modules[module_name] = Application.objects.get(python_name=module_name)
             else:
@@ -163,7 +171,7 @@ class _Registry:
         entry_url = module_entry.menu_name + '_' + entry.url_name + '_' + action.name
         entry.url = entry_url
         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))
         model_actions[action.name] = entry
         self._models[model] = model_actions
@@ -172,10 +180,9 @@ class _Registry:
             url_path += '/%s' % action.url_parameters
         return url(url_path+'/?$', action.view_factory(model=entry.model, **kwargs), name=entry_url)
 
-
     def get_url_of_action(self, model, action_name, **kwargs):
         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)
 
     def modules(self):
@@ -185,7 +192,7 @@ class _Registry:
         return [x.menu_name for x in self._modules.values()]
 
     def is_controlled(self, model):
-        return self._models.has_key(model)
+        return model in self._models
 
     def model_entry(self, model):
         return self._models.get(model)

+ 7 - 5
src/rapid/urls.py

@@ -1,6 +1,9 @@
 # -*- 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
 
@@ -27,8 +30,7 @@ _manage_users_permission = permissions.Permission(
 
 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.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')
-

+ 8 - 0
src/rapid/views.py

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

+ 17 - 11
src/rapid/widgets.py

@@ -1,26 +1,32 @@
 # -*- 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.template import loader, Context
+from django.utils.encoding import force_text
 
 from rapid.wrappers import ModelData
 
 _templates_root = 'rapid/widgets/'
 
+
 class RapidReadOnly(widgets.Widget):
     def render(self, name, value, attrs=None):
         hidden = '<input type="hidden" name="%s" value="%s" ' % (name, value)
         for a in attrs.keys():
             hidden += '%s="%s" ' % (a, attrs[a])
         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):
         return data[name]
 
+
 class RapidRelationReadOnly(widgets.Widget):
     def __init__(self, model, *args, **kwargs):
         super(RapidRelationReadOnly, self).__init__(*args, **kwargs)
@@ -32,15 +38,15 @@ class RapidRelationReadOnly(widgets.Widget):
             hidden += '%s="%s" ' % (a, attrs[a])
         hidden += '>'
         if hasattr(value, '__iter__'):
-            objs = self.model.default_manager().filter(pk__in=value)
+            obj = self.model.default_manager().filter(pk__in=value)
             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
             return ret
         else:
             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):
         return data[name]
@@ -61,7 +67,7 @@ class RapidSelector(widgets.Select):
         self.remove_deselected = relation.is_weak()
 
     def render(self, name, value, attrs=None, choices=()):
-        id = attrs.get('id', name)
+        tp_id = attrs.get('id', name)
         related = self.relation.related_model()
         if self.allow_multiple_selected:
             if value:
@@ -84,8 +90,8 @@ class RapidSelector(widgets.Select):
                 icon = 'fa-trash-o'
         else:
             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:
             t = loader.get_template(_templates_root + 'multiple-selector.html')
         else:
@@ -104,7 +110,7 @@ class RapidSelector(widgets.Select):
             return None
 
 
-def rapidAlternativesWidget(alternatives, selector):
+def rapid_alternatives_widget(alternatives, selector):
     class RapidAlternativeFormsWidget(widgets.Widget):
         def render(self, name, value, attrs=None):
             attrs = attrs if attrs else []

+ 23 - 19
src/rapid/wrappers.py

@@ -1,8 +1,12 @@
 # -*- 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 import filters
@@ -12,7 +16,7 @@ from django.db import models
 from rapid import permissions
 
 
-class InstanceData:
+class InstanceData(object):
     def __init__(self, instance, request=None, excludes=None, creator=None, fields=None):
         excludes = [] if excludes is None else excludes
         self.model = ModelData(type(instance), request, excludes, creator, fields)
@@ -133,13 +137,13 @@ class InstanceData:
         return False
 
     def __unicode__(self):
-        return unicode(self.instance)
+        return force_text(self.instance)
 
     def __str__(self):
         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):
         excludes = [] if excludes is None else excludes
         self.model = model
@@ -150,11 +154,11 @@ class ModelData:
 
     def model_name(self):
         # noinspection PyProtectedMember
-        return unicode(self.model._meta.verbose_name)
+        return force_text(self.model._meta.verbose_name)
 
     def model_name_plural(self):
         # noinspection PyProtectedMember
-        return unicode(self.model._meta.verbose_name_plural)
+        return force_text(self.model._meta.verbose_name_plural)
 
     def default_manager(self):
         # noinspection PyProtectedMember
@@ -209,7 +213,7 @@ class ModelData:
 
         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:
                 yield (k, v)
 
@@ -270,13 +274,13 @@ class ModelData:
         return ContentType.objects.get_for_model(self.model)
 
     def __unicode__(self):
-        return unicode(self.model)
+        return force_text(self.model)
 
     def __str__(self):
         return 'Model: ' + str(self.model)
 
 
-class FieldData:
+class FieldData(object):
     def __init__(self, field, request=None):
         self.field = field
         self.request = request
@@ -285,30 +289,30 @@ class FieldData:
     def from_model(cls, model, field_name):
         ff = ModelData(model).fields()
         for f in ff:
-            if f.bare_name() == unicode(field_name):
+            if f.bare_name() == force_text(field_name):
                 return f
         return None
 
     def bare_name(self):
-        return unicode(self.field.name)
+        return force_text(self.field.name)
 
     def accessor_name(self):
         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):
         if self.is_auto() and self.is_relation():
             return self.related_model().model_name_plural() + u' - ' + self.related_field().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):
         if self.is_auto() and self.is_relation():
             return self.related_model().model_name_plural() + u' - ' + self.related_field().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"
 
     def is_relation(self):
@@ -364,7 +368,7 @@ class FieldData:
         return self.bare_name()
 
 
-class ValueData:
+class ValueData(object):
     def __init__(self, value, field):
         self.value = value
         self.field = field