4 Комити 770e53981a ... b1adc789ea

Аутор SHA1 Порука Датум
  Marcos Dumay de Medeiros b1adc789ea Archiving пре 3 година
  Marcos Dumay de Medeiros 774ddf0d17 Using Django Datetime Widget пре 7 година
  Marcos Dumay de Medeiros 019b6a4177 More small fixes пре 7 година
  Marcos Dumay de Medeiros 758123f1fc Radom small fixes пре 7 година

+ 2 - 1
TODO

@@ -1,7 +1,8 @@
-Many2many does not appear in list
 Export data to csv
 Export data to csv
 Go to page number
 Go to page number
 Filter for all basic types
 Filter for all basic types
 Form fields for reverse relations
 Form fields for reverse relations
+    Fix appearance of deleted forms
 Union and disjunction of permissions
 Union and disjunction of permissions
 Multiple registering of actions
 Multiple registering of actions
+Type annotations. Lots of them.

+ 7 - 6
setup.py

@@ -4,22 +4,23 @@ __author__ = 'marcos.medeiros'
 """
 """
 
 
 # Always prefer setuptools over distutils
 # Always prefer setuptools over distutils
-from setuptools import setup, find_packages
+from setuptools import setup  # find_packages
 # To use a consistent encoding
 # To use a consistent encoding
 from codecs import open
 from codecs import open
 import os
 import os
 from os import path
 from os import path
 
 
+
 def _recursive_find(root, p):
 def _recursive_find(root, p):
     full_p = path.join(root, p)
     full_p = path.join(root, p)
-    for f in os.listdir(full_p):
-        full_f = path.join(full_p, f)
-        val_f = path.join(p, f)
+    for fl in os.listdir(full_p):
+        full_f = path.join(full_p, fl)
+        val_f = path.join(p, fl)
         if path.isdir(full_f):
         if path.isdir(full_f):
             for ff in _recursive_find(root, val_f):
             for ff in _recursive_find(root, val_f):
                 yield ff
                 yield ff
         else:
         else:
-             yield val_f
+            yield val_f
 
 
 
 
 here = path.abspath(path.dirname(__file__))
 here = path.abspath(path.dirname(__file__))
@@ -81,7 +82,7 @@ setup(
     # your project is installed. For an analysis of "install_requires" vs pip's
     # your project is installed. For an analysis of "install_requires" vs pip's
     # requirements files see:
     # requirements files see:
     # https://packaging.python.org/en/latest/requirements.html
     # https://packaging.python.org/en/latest/requirements.html
-    install_requires=['django>=1.8', 'django-datetime-widget>=0.9', 'django-migration-fixture>=0.5', 'six'],
+    install_requires=['django==1.8', 'django-datetime-widget>=0.9', 'django-migration-fixture>=0.5', 'six'],
 
 
     # List additional groups of dependencies here (e.g. development
     # List additional groups of dependencies here (e.g. development
     # dependencies). You can install these using the following syntax,
     # dependencies). You can install these using the following syntax,

+ 2 - 2
src/rapid/forms.py

@@ -10,7 +10,7 @@ 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
+from rapid.widgets import RapidReadOnly, RapidSelector, getRapidReadonlyRelation
 
 
 
 
 class ManageUsers(forms.ModelForm):
 class ManageUsers(forms.ModelForm):
@@ -18,7 +18,7 @@ class ManageUsers(forms.ModelForm):
         model = Profile
         model = Profile
         fields = '__all__'
         fields = '__all__'
         widgets = {
         widgets = {
-            'application': RapidRelationReadOnly(Application),
+            'application': getRapidReadonlyRelation(Application, None),
             'name': RapidReadOnly(),
             'name': RapidReadOnly(),
             'description': RapidReadOnly,
             'description': RapidReadOnly,
             'users': RapidSelector(FieldData.from_model(Profile, 'users'))
             'users': RapidSelector(FieldData.from_model(Profile, 'users'))

+ 23 - 4
src/rapid/rapidforms.py

@@ -8,12 +8,16 @@ from __future__ import unicode_literals
 import collections
 import collections
 
 
 from django import forms
 from django import forms
+from django.db import models
+from django.conf import settings
 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
 from django.utils.encoding import force_text
 from django.utils.encoding import force_text
+from datetimewidget import widgets as dtwidgets
 
 
-from rapid.widgets import RapidSelector, RapidRelationReadOnly, rapid_alternatives_widget, rapid_dependent_widget
+from rapid.widgets import RapidSelector, rapid_alternatives_widget, rapid_dependent_widget, \
+    getRapidReadonlyRelation
 from rapid.wrappers import FieldData, ModelData
 from rapid.wrappers import FieldData, ModelData
 
 
 import gettext
 import gettext
@@ -114,6 +118,8 @@ class RapidDependentField(forms.Field):
 
 
 
 
 def for_model(request, model, default_relations=()):
 def for_model(request, model, default_relations=()):
+    hasDtWidgets = 'datetimewidget' in settings.INSTALLED_APPS
+
     default_relations = list(default_relations)
     default_relations = list(default_relations)
     default_relations_request = request.GET.get('default')
     default_relations_request = request.GET.get('default')
     widgets = []
     widgets = []
@@ -124,12 +130,24 @@ def for_model(request, model, default_relations=()):
         default_relations_fields = [x for x, y in default_relations]
         default_relations_fields = [x for x, y in default_relations]
     for (x, y) in default_relations:
     for (x, y) in default_relations:
         f = FieldData(getattr(model, x).field, request)
         f = FieldData(getattr(model, x).field, request)
-        widgets.append((x, RapidRelationReadOnly(f.related_model().model)))
+        widgets.append((x, getRapidReadonlyRelation(f.related_model().model, y)))
         default_relations_fields.append(x)
         default_relations_fields.append(x)
     for f in ModelData(model).local_fields():
     for f in ModelData(model).local_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.is_relation():
+            if force_text(f.bare_name()) not in default_relations_fields and \
+            f.related_model().has_permission(request, 'select'):
                 widgets.append((f.bare_name(), RapidSelector(f)))
                 widgets.append((f.bare_name(), RapidSelector(f)))
+            elif force_text(f.bare_name()) in default_relations_fields:
+                pass
+        if type(f.field) == models.DateField:
+            widgets.append((f.bare_name(), dtwidgets.DateWidget(usel10n = True, bootstrap_version=3)))
+        if type(f.field) == models.DateTimeField:
+            widgets.append((f.bare_name(), dtwidgets.DateTimeWidget(usel10n = True, bootstrap_version=3)))
+        if type(f.field) == models.TimeField:
+            widgets.append((f.bare_name(), dtwidgets.TimeWidget(usel10n = True, bootstrap_version=3)))
+
+    #if force_text(model._meta.db_table) == 'testproject_singledepontest1':
+    #    import pdb; pdb.set_trace()
     # 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
     form_model = model
     form_model = model
     form_widgets = dict(widgets)
     form_widgets = dict(widgets)
@@ -178,6 +196,7 @@ def for_model(request, model, default_relations=()):
 
 
         @transaction.atomic
         @transaction.atomic
         def save(self, commit=True):
         def save(self, commit=True):
+
             if not commit:
             if not commit:
                 return super(CForm, self).save(commit)
                 return super(CForm, self).save(commit)
             else:
             else:

+ 3 - 2
src/rapid/registry.py

@@ -157,11 +157,12 @@ class _Registry(object):
             raise Exception("Unidentified python module registering " + str(model))
             raise Exception("Unidentified python module registering " + str(model))
         if module_name not in registry._modules:
         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)
+                a = Application.objects.get(python_name=module_name)
+                registry._modules[module_name] = ModuleEntry(a.python_name, a.name)
             else:
             else:
                 a = Application(name=module_name, python_name=module_name)
                 a = Application(name=module_name, python_name=module_name)
                 a.save()
                 a.save()
-                registry._modules[module_name] = a
+                registry._modules[module_name] = ModuleEntry(a.python_name, a.name)
 
 
         module_entry = registry._modules[module_name]
         module_entry = registry._modules[module_name]
         module_entry.models.add(model)
         module_entry.models.add(model)

+ 1 - 0
src/rapid/templates/rapid/bare/create.html

@@ -1,3 +1,4 @@
+{{ form.media }}
 <h2>{{object_data.model_name.title}}</h2>
 <h2>{{object_data.model_name.title}}</h2>
 
 
 <form method="POST" action="" enctype="multipart/form-data">
 <form method="POST" action="" enctype="multipart/form-data">

+ 1 - 0
src/rapid/templates/rapid/bare/update.html

@@ -1,3 +1,4 @@
+{{ form.media }}
 <h2>{{object_data.model_name.title}}</h2>
 <h2>{{object_data.model_name.title}}</h2>
 
 
 <form method="POST" action=""  enctype="multipart/form-data">
 <form method="POST" action=""  enctype="multipart/form-data">

+ 21 - 4
src/rapid/templates/rapid/widgets/multipleDependent.html

@@ -8,16 +8,20 @@
         border-style: solid;
         border-style: solid;
         padding: 1em;
         padding: 1em;
     }
     }
-    .deleted{
+    .deleted *:not(.toggle-remove){
         text-decoration: line-through;
         text-decoration: line-through;
     }
     }
+    .included-dependent-checkbox{
+        display: none;
+    }
 </style>
 </style>
 <div id="forms-for-{{ formset.prefix }}">
 <div id="forms-for-{{ formset.prefix }}">
     {% for form in formset %}
     {% for form in formset %}
         <div class="rapid-singledependent {{ formset.prefix }} form">
         <div class="rapid-singledependent {{ formset.prefix }} form">
-            <input type="checkbox" class="includes_{{ formset.prefix }}"
-                   name="includes_{{ form.prefix }}" checked="true">
+            <input type="checkbox" class="includes_{{ formset.prefix }} included-dependent-checkbox"
+                   name="includes_{{ form.prefix }}" checked>
             {{ form.as_p }}
             {{ form.as_p }}
+            <input type="button" value="Remover" class="toggle-remove">
         </div>
         </div>
     {% endfor %}
     {% endfor %}
 </div>
 </div>
@@ -29,8 +33,21 @@
     $("#add-form-in-{{ formset.prefix }}").click(function(){
     $("#add-form-in-{{ formset.prefix }}").click(function(){
         var formcount = $("#forms-for-{{ formset.prefix }}").children("div").length;
         var formcount = $("#forms-for-{{ formset.prefix }}").children("div").length;
         $("#id_{{ formset.prefix }}-TOTAL_FORMS").val(formcount + 1);
         $("#id_{{ formset.prefix }}-TOTAL_FORMS").val(formcount + 1);
-        var empty = "<div class=\"rapid-singledependent {{ formset.prefix }} form\">\n<input type=\"checkbox\" class=\"includes_{{ formset.prefix }}\" name=\"includes_{{ formset.prefix }}-__prefix__\" checked=\"true\">\n{{ formset.empty_form.as_p|jsstr }}\n<\div>";
+        var empty = "<div class=\"rapid-singledependent {{ formset.prefix }} form\">\n<input type=\"checkbox\" class=\"includes_{{ formset.prefix }} included-dependent-checkbox\" name=\"includes_{{ formset.prefix }}-__prefix__\" checked=\"true\">\n{{ formset.empty_form.as_p|jsstr }}\n<input type=\"button\" value=\"Apagar\" id=\"toggle-remove\">\n<\div>";
         $("#forms-for-{{ formset.prefix }}").append(empty.replace(/__prefix__/g, formcount));
         $("#forms-for-{{ formset.prefix }}").append(empty.replace(/__prefix__/g, formcount));
     });
     });
+    $("#forms-for-{{ formset.prefix }} .included-dependent-checkbox").change(function(){
+        $(this).parent().toggleClass("deleted");
+    });
+    $("#forms-for-{{ formset.prefix }} .toggle-remove").click(function(){
+        var box = $(this).parent().children(".included-dependent-checkbox")
+        var vis = box.prop("checked");
+        box.prop("checked", !vis);
+        box.parent().toggleClass("deleted");
+        if(vis)
+            $(this).prop("value", "Incluir");
+        else
+            $(this).prop("value", "Remover");
+    });
 </script>
 </script>
 </div>
 </div>

+ 24 - 2
src/rapid/templates/rapid/widgets/singleDependent.html

@@ -1,4 +1,4 @@
-<div>
+<div id="form-for-{{ name }}">
 <style scoped>
 <style scoped>
     .rapid-dependent{
     .rapid-dependent{
         border-width: 1px;
         border-width: 1px;
@@ -9,14 +9,36 @@
     .hidden{
     .hidden{
         display: none;
         display: none;
     }
     }
+    .deleted{
+        text-decoration: line-through;
+    }
+    .included-dependent-checkbox{
+        display: none;
+    }
 </style>
 </style>
-<input type="checkbox" id="includes_{{ name }}" name="includes_{{ name }}"{% if present %} checked{% endif %}>
+<input type="checkbox" class="included-dependent-checkbox" id="includes_{{ name }}"
+       name="includes_{{ name }}"{% if present %} checked{% endif %}>
 <div class="rapid-dependent {{ name }} form{% if not present %} hidden{% endif %}">
 <div class="rapid-dependent {{ name }} form{% if not present %} hidden{% endif %}">
     {{ form.as_p }}
     {{ form.as_p }}
 </div>
 </div>
+<input type="button" value="{% if present %}Remover{% else %}Incluir{% endif %}" class="toggle-remove">
 <script>
 <script>
     $("#includes_{{ name }}").change(function(){
     $("#includes_{{ name }}").change(function(){
         $("div.{{ name }}.form").toggleClass("hidden");
         $("div.{{ name }}.form").toggleClass("hidden");
     });
     });
+    $("#form-for-{{ name }} .included-dependent-checkbox").change(function(){
+        $(this).parent().toggleClass("deleted");
+    });
+    $("#form-for-{{ name }} .toggle-remove").click(function(){
+        var box = $(this).parent().children(".included-dependent-checkbox");
+        var vis = box.prop("checked");
+        box.prop("checked", !vis);
+        if (vis) {
+            $(this).prop("value", "Incluir");
+        } else {
+            $(this).prop("value", "Remover");
+        }
+        $("div.{{ name }}.form").toggleClass("hidden");
+    });
 </script>
 </script>
 </div>
 </div>

+ 25 - 27
src/rapid/widgets.py

@@ -17,40 +17,40 @@ _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 if value else "")
         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' % (force_text(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.get(name)
 
 
 
 
-class RapidRelationReadOnly(widgets.Widget):
-    def __init__(self, model, *args, **kwargs):
-        super(RapidRelationReadOnly, self).__init__(*args, **kwargs)
-        self.model = ModelData(model)
-
-    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 += '>'
-        if hasattr(value, '__iter__'):
-            obj = self.model.default_manager().filter(pk__in=value)
-            ret = ''
-            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' % (force_text(obj), hidden)
-
-    def value_from_datadict(self, data, files, name):
-        return data[name]
+def getRapidReadonlyRelation(model, originator):
+    class RapidRelationReadOnly(widgets.Widget):
+        def render(self, name, value, attrs=None):
+            hidden = '<input type="hidden" name="%s" value="%s" ' % (name, value if value else "")
+            for a in attrs.keys():
+                hidden += '%s="%s" ' % (a, attrs[a])
+            hidden += '>'
+            if hasattr(value, '__iter__'):
+                obj = model.default_manager().filter(pk__in=value)
+                ret = ''
+                for o in obj:
+                    ret += '<span class="data-value multiple">%s</span>\n' % force_text(o)
+                ret += hidden
+                return ret
+            else:
+                if value:
+                    obj = model.default_manager().get(pk=value)
+                else:
+                    obj = ""
+                return '<span class="data-value">%s</span>%s\n' % (force_text(obj), hidden)
 
 
+        def value_from_datadict(self, data, files, name):
+            return originator
+    return RapidRelationReadOnly
 
 
 class RapidSelector(widgets.Select):
 class RapidSelector(widgets.Select):
     """
     """
@@ -132,7 +132,6 @@ def rapid_alternatives_widget(alternatives, selector):
     return RapidAlternativeFormsWidget
     return RapidAlternativeFormsWidget
 
 
 
 
-#TODO: Finish it!
 def rapid_dependent_widget(model_data, form, has_instance, is_mutiple):
 def rapid_dependent_widget(model_data, form, has_instance, is_mutiple):
     class RapidDependentWidget(widgets.Widget):
     class RapidDependentWidget(widgets.Widget):
         # What to ask:
         # What to ask:
@@ -153,7 +152,6 @@ def rapid_dependent_widget(model_data, form, has_instance, is_mutiple):
                  'form': form,
                  'form': form,
                  'present': has_instance,
                  'present': has_instance,
                  })
                  })
-            # import pdb; pdb.set_trace()
             t = loader.get_template(_templates_root + ('multipleDependent.html' if
             t = loader.get_template(_templates_root + ('multipleDependent.html' if
                                     is_mutiple else 'singleDependent.html'))
                                     is_mutiple else 'singleDependent.html'))
             return t.render(c)
             return t.render(c)

+ 2 - 0
testproject/testproject/settings.py

@@ -40,6 +40,7 @@ INSTALLED_APPS = (
     'testproject',
     'testproject',
     'rapid',
     'rapid',
     'django_migration_fixture',
     'django_migration_fixture',
+    'datetimewidget',
 )
 )
 
 
 MIDDLEWARE_CLASSES = (
 MIDDLEWARE_CLASSES = (
@@ -51,6 +52,7 @@ MIDDLEWARE_CLASSES = (
     'django.contrib.messages.middleware.MessageMiddleware',
     'django.contrib.messages.middleware.MessageMiddleware',
     'django.middleware.clickjacking.XFrameOptionsMiddleware',
     'django.middleware.clickjacking.XFrameOptionsMiddleware',
     'django.middleware.security.SecurityMiddleware',
     'django.middleware.security.SecurityMiddleware',
+    'django.middleware.locale.LocaleMiddleware',
 )
 )
 
 
 ROOT_URLCONF = 'testproject.urls'
 ROOT_URLCONF = 'testproject.urls'

+ 2 - 1
testproject/testproject/templates/base.html

@@ -5,11 +5,12 @@
     <meta charset="utf-8">
     <meta charset="utf-8">
     <meta name="viewport" content="width=device-width, initial-scale=1">
     <meta name="viewport" content="width=device-width, initial-scale=1">
     <title>{% block title %}Rapid Test Site{% endblock %}</title>
     <title>{% block title %}Rapid Test Site{% endblock %}</title>
+    <script src="{% static 'js/jquery.js' %}"></script>
     <link href="{% static 'css/bootstrap.css' %}" rel="stylesheet">
     <link href="{% static 'css/bootstrap.css' %}" rel="stylesheet">
+    <script src="{% static 'js/bootstrap.js' %}"></script>
     <link href="{% static 'css/bootstrap-theme.css' %}" rel="stylesheet">
     <link href="{% static 'css/bootstrap-theme.css' %}" rel="stylesheet">
     <link href="{% static 'css/font-awesome.css' %}" rel="stylesheet">
     <link href="{% static 'css/font-awesome.css' %}" rel="stylesheet">
     <link href="{% static 'css/base.css' %}" rel="stylesheet">
     <link href="{% static 'css/base.css' %}" rel="stylesheet">
-    <script src="{% static 'js/jquery.js' %}"></script>
     <style>
     <style>
         div#head{
         div#head{
             margin-top: 2em;
             margin-top: 2em;