Parcourir la source

Merge branch 'dev'

Denis K il y a 8 ans
Parent
commit
05b543368c
34 fichiers modifiés avec 236 ajouts et 87 suppressions
  1. 32 15
      .travis.yml
  2. 14 0
      CHANGELOG.rst
  3. 79 28
      docs/config_file.rst
  4. 1 1
      jet/__init__.py
  5. 9 8
      jet/dashboard/dashboard.py
  6. 5 1
      jet/dashboard/dashboard_modules/google_analytics.py
  7. 5 1
      jet/dashboard/dashboard_modules/google_analytics_views.py
  8. 5 1
      jet/dashboard/dashboard_modules/yandex_metrika.py
  9. 5 1
      jet/dashboard/dashboard_modules/yandex_metrika_views.py
  10. 2 2
      jet/dashboard/modules.py
  11. 5 1
      jet/dashboard/views.py
  12. 4 1
      jet/filters.py
  13. 1 1
      jet/management/commands/jet_side_menu_items_example.py
  14. 1 1
      jet/static/jet/css/_sidebar.scss
  15. 0 0
      jet/static/jet/css/themes/default/base.css
  16. 0 0
      jet/static/jet/css/themes/default/base.css.map
  17. 0 0
      jet/static/jet/css/themes/green/base.css
  18. 0 0
      jet/static/jet/css/themes/green/base.css.map
  19. 0 0
      jet/static/jet/css/themes/light-blue/base.css
  20. 0 0
      jet/static/jet/css/themes/light-blue/base.css.map
  21. 0 0
      jet/static/jet/css/themes/light-gray/base.css
  22. 0 0
      jet/static/jet/css/themes/light-gray/base.css.map
  23. 0 0
      jet/static/jet/css/themes/light-green/base.css
  24. 0 0
      jet/static/jet/css/themes/light-green/base.css.map
  25. 0 0
      jet/static/jet/css/themes/light-violet/base.css
  26. 0 0
      jet/static/jet/css/themes/light-violet/base.css.map
  27. 0 0
      jet/static/jet/css/vendor.css
  28. 3 3
      jet/templates/admin/base.html
  29. 6 3
      jet/templatetags/jet_tags.py
  30. 5 1
      jet/tests/test_dashboard.py
  31. 10 6
      jet/tests/test_tags.py
  32. 5 1
      jet/tests/test_views.py
  33. 32 11
      jet/utils.py
  34. 7 0
      setup.py

+ 32 - 15
.travis.yml

@@ -5,18 +5,21 @@ python:
   - 3.2
   - 3.2
   - 3.3
   - 3.3
   - 3.4
   - 3.4
+  - 3.5
+  - 3.6
   - pypy
   - pypy
 env:
 env:
-  - DJANGO=1.6.11
-  - DJANGO=1.7.7
-  - DJANGO=1.8.3
-  - DJANGO=1.9.8
-  - DJANGO=1.10.0
+  - DJANGO="<1.7"
+  - DJANGO="<1.8"
+  - DJANGO="<1.9"
+  - DJANGO="<1.10"
+  - DJANGO="<1.11"
+  - DJANGO="<1.12"
 before_install:
 before_install:
   - export DJANGO_SETTINGS_MODULE=jet.tests.settings
   - export DJANGO_SETTINGS_MODULE=jet.tests.settings
 install:
 install:
-  - pip install -q Django==$DJANGO --use-mirrors
-  - pip install . --use-mirrors
+  - pip install -q "Django${DJANGO}"
+  - pip install .
   - pip install coverage==3.7.1
   - pip install coverage==3.7.1
   - pip install coveralls==0.5
   - pip install coveralls==0.5
 script:
 script:
@@ -27,18 +30,32 @@ after_success:
 matrix:
 matrix:
   exclude:
   exclude:
     - python: 2.6
     - python: 2.6
-      env: DJANGO=1.7.7
+      env: DJANGO="<1.8"
     - python: 2.6
     - python: 2.6
-      env: DJANGO=1.8.3
+      env: DJANGO="<1.9"
     - python: 2.6
     - python: 2.6
-      env: DJANGO=1.9.8
+      env: DJANGO="<1.10"
     - python: 3.2
     - python: 3.2
-      env: DJANGO=1.9.8
+      env: DJANGO="<1.10"
     - python: 3.3
     - python: 3.3
-      env: DJANGO=1.9.8
+      env: DJANGO="<1.10"
     - python: 2.6
     - python: 2.6
-      env: DJANGO=1.10.0
+      env: DJANGO="<1.11"
     - python: 3.2
     - python: 3.2
-      env: DJANGO=1.10.0
+      env: DJANGO="<1.11"
     - python: 3.3
     - python: 3.3
-      env: DJANGO=1.10.0
+      env: DJANGO="<1.11"
+    - python: 2.6
+      env: DJANGO="<1.12"
+    - python: 3.2
+      env: DJANGO="<1.12"
+    - python: 3.3
+      env: DJANGO="<1.12"
+    - python: 3.5
+      env: DJANGO="<1.7"
+    - python: 3.5
+      env: DJANGO="<1.8"
+    - python: 3.6
+      env: DJANGO="<1.7"
+    - python: 3.6
+      env: DJANGO="<1.8"

+ 14 - 0
CHANGELOG.rst

@@ -1,6 +1,20 @@
 Changelog
 Changelog
 =========
 =========
 
 
+1.0.6
+-----
+* PR-191: Added sidebar pinning functionality (thanks to grigory51 for PR)
+* Issue-199: Fixed Django 1.11 context issue (thanks to gileadslostson for report)
+* Issue-202: Fixed inline-group-row:added event (thanks to a1Gupta for report)
+* Issue-188: Make testing use latest major Django versions and Python 3.5, 3.6 (thanks to liminspace for report)
+* Added new flexible menu customizing setting JET_SIDE_MENU_ITEMS
+* Added labels to sibling buttons
+* Fixed django.jQuery select change events
+* Fixed sidebar "Search..." label localization
+* Added select disabled style
+* Fixed initial value for select2 ajax fields when POST request
+
+
 1.0.5
 1.0.5
 -----
 -----
 * PR-167: Added fallback to window.opener to support old Django popups (thanks to michaelkuty for PR)
 * PR-167: Added fallback to window.opener to support old Django popups (thanks to michaelkuty for PR)

+ 79 - 28
docs/config_file.rst

@@ -95,61 +95,112 @@ CUSTOM MENU
 -----------
 -----------
 
 
 By default JET displays all applications and it models in the side menu in the alphabetical order.
 By default JET displays all applications and it models in the side menu in the alphabetical order.
-To display applications and models you want or to change their order you can use ``JET_SIDE_MENU_CUSTOM_APPS`` setting.
+To display applications and models you want or to change their order you can use ``JET_SIDE_MENU_ITEMS`` setting.
 
 
 .. code:: python
 .. code:: python
 
 
-    JET_SIDE_MENU_CUSTOM_APPS = [
-        ('core', [ # Each list element is a tuple with application name (app_label) and list of models
-            'User',
-            'MenuItem',
-            'Block',
-        ]),
-        ('shops', [
-            'Shop',
-            'City',
-            'MetroStation',
-        ]),
-        ('feedback', [
-            'Feedback',
-        ]),
+    JET_SIDE_MENU_ITEMS = [  # A list of application or custom item dicts
+        {'label': _('General'), 'app_label': 'core', 'items': [
+            {'name': 'help.question'},
+            {'name': 'pages.page', 'label': _('Static page')},
+            {'name': 'city'},
+            {'name': 'validationcode'},
+            {'label': _('Analytics'), 'url': 'http://example.com', 'url_blank': True},
+        ]},
+        {'label': _('Users'), 'items': [
+            {'name': 'core.user'},
+            {'name': 'auth.group'},
+            {'name': 'core.userprofile', 'permissions': ['core.user']},
+        ]},
+        {'app_label': 'banners', 'items': [
+            {'name': 'banner'},
+            {'name': 'bannertype'},
+        ]},
     ]
     ]
 
 
-If want to show all application's models use ``__all__`` keyword.
+JET_SIDE_MENU_ITEMS is a list of application or custom item dicts. Each item can have the following keys:
 
 
-.. code:: python
+* `app_label` - application name
+* `label` - application text label
+* `items` - list of children items
+* `url` - custom url (format is described below)
+* `url_blank` - open url in new table (boolean)
+* `permissions` - list of required permissions to display item
 
 
-    JET_SIDE_MENU_CUSTOM_APPS = [
-        ('core', ['__all__']),
-        ...
-    ]
+Setting `items` and either `app_label` or `label` is required. Other keys are optional to override default behavior.
+Order of items is respected. Each menu item is also a dict with the following keys:
+
+* `name` - model name (can be either `MODEL_NAME` or `APP_LABEL.MODEL_NAME`)
+* `label` - item text label
+* `url` - custom url (format is described below)
+* `url_blank` - open url in new table (boolean)
+* `permissions` - list of required permissions to display item
+
+Setting either `name` or `label` is required. Other keys are optional to override default behavior.
+Order of items is respected.
+
+URLs can be either `string` or `dict`. Examples of possible values:
+
+* http://example.com/
+* {'type': 'app', 'app_label': 'pages'}
+* {'type': 'model', 'app_label': 'pages', 'model': 'page'}
+* {'type': 'reverse', 'name': 'pages:list', 'args': [1], 'kwargs': {'category': 2}}
+
+.. deprecated:: 1.0.6
+
+    Old way of customizing menu items via `JET_SIDE_MENU_CUSTOM_APPS` setting is now deprecated in favor
+    of new `JET_SIDE_MENU_ITEMS` setting.
+
+    .. code:: python
+
+        JET_SIDE_MENU_CUSTOM_APPS = [
+            ('core', [ # Each list element is a tuple with application name (app_label) and list of models
+                'User',
+                'MenuItem',
+                'Block',
+            ]),
+            ('shops', [
+                'Shop',
+                'City',
+                'MetroStation',
+            ]),
+            ('feedback', [
+                'Feedback',
+            ]),
+        ]
 
 
 If have multiple admin sites and you want to specify different menu applications for each admin site, wrap menu lists
 If have multiple admin sites and you want to specify different menu applications for each admin site, wrap menu lists
 in dictionary with admin site names as keys:
 in dictionary with admin site names as keys:
 
 
 .. code:: python
 .. code:: python
 
 
-    JET_SIDE_MENU_CUSTOM_APPS = {
+    JET_SIDE_MENU_ITEMS = {
         'admin': [
         'admin': [
-            ('core', ['__all__']),
+            {'label': _('General'), 'app_label': 'core', 'items': [
+                {'name': 'help.question'},
+                {'name': 'pages.page'},
+                {'name': 'city'},
+                {'name': 'validationcode'},
+            ]},
             ...
             ...
         ],
         ],
         'custom_admin': [
         'custom_admin': [
-            ('custom_admin_app', [
-                'CustomAdminAppModel',
-            ]),
+            {'app_label': 'talks', 'items': [
+                {'name': 'talk'},
+                {'name': 'talkmessage'},
+            ]},
             ...
             ...
         ]
         ]
     }
     }
 
 
 .. note::
 .. note::
 
 
-    You can use ``jet_custom_apps_example`` management command to generate example ``JET_SIDE_MENU_CUSTOM_APPS``
+    You can use ``jet_side_menu_items_example`` management command to generate example ``JET_SIDE_MENU_ITEMS``
     setting which includes all your applications and models. You can use it this way:
     setting which includes all your applications and models. You can use it this way:
 
 
     .. code:: python
     .. code:: python
 
 
-        python manage.py jet_custom_apps_example
+        python manage.py jet_side_menu_items_example
 
 
 JET_CHANGE_FORM_SIBLING_LINKS
 JET_CHANGE_FORM_SIBLING_LINKS
 -----------------------------
 -----------------------------

+ 1 - 1
jet/__init__.py

@@ -1 +1 @@
-VERSION = '1.0.5'
+VERSION = '1.0.6'

+ 9 - 8
jet/dashboard/dashboard.py

@@ -1,12 +1,16 @@
-from django.template import Context
 from importlib import import_module
 from importlib import import_module
-from django.core.urlresolvers import reverse
+try:
+    from django.core.urlresolvers import reverse
+except ImportError: # Django 1.11
+    from django.urls import reverse
+
 from django.template.loader import render_to_string
 from django.template.loader import render_to_string
 from jet.dashboard import modules
 from jet.dashboard import modules
 from jet.dashboard.models import UserDashboardModule
 from jet.dashboard.models import UserDashboardModule
 from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import ugettext_lazy as _
 from jet.ordered_set import OrderedSet
 from jet.ordered_set import OrderedSet
-from jet.utils import get_admin_site_name
+from jet.utils import get_admin_site_name, context_to_dict
+
 try:
 try:
     from django.template.context_processors import csrf
     from django.template.context_processors import csrf
 except ImportError:
 except ImportError:
@@ -48,9 +52,6 @@ class Dashboard(object):
         self.set_context(context)
         self.set_context(context)
 
 
     def set_context(self, context):
     def set_context(self, context):
-        if isinstance(context, Context):
-            context = context.flatten()
-
         self.context = context
         self.context = context
         self.init_with_context(context)
         self.init_with_context(context)
         self.load_modules()
         self.load_modules()
@@ -150,7 +151,7 @@ class Dashboard(object):
         self.modules = loaded_modules
         self.modules = loaded_modules
 
 
     def render(self):
     def render(self):
-        context = self.context
+        context = context_to_dict(self.context)
         context.update({
         context.update({
             'columns': range(self.columns),
             'columns': range(self.columns),
             'modules': self.modules,
             'modules': self.modules,
@@ -161,7 +162,7 @@ class Dashboard(object):
         return render_to_string('jet.dashboard/dashboard.html', context)
         return render_to_string('jet.dashboard/dashboard.html', context)
 
 
     def render_tools(self):
     def render_tools(self):
-        context = self.context
+        context = context_to_dict(self.context)
         context.update({
         context.update({
             'children': self.children,
             'children': self.children,
             'app_label': self.app_label,
             'app_label': self.app_label,

+ 5 - 1
jet/dashboard/dashboard_modules/google_analytics.py

@@ -2,7 +2,11 @@
 import datetime
 import datetime
 import json
 import json
 from django import forms
 from django import forms
-from django.core.urlresolvers import reverse
+try:
+    from django.core.urlresolvers import reverse
+except ImportError: # Django 1.11
+    from django.urls import reverse
+
 from django.forms import Widget
 from django.forms import Widget
 from django.utils import formats
 from django.utils import formats
 from django.utils.html import format_html
 from django.utils.html import format_html

+ 5 - 1
jet/dashboard/dashboard_modules/google_analytics_views.py

@@ -1,4 +1,8 @@
-from django.core.urlresolvers import reverse
+try:
+    from django.core.urlresolvers import reverse
+except ImportError: # Django 1.11
+    from django.urls import reverse
+
 from django.conf.urls import url
 from django.conf.urls import url
 from django.contrib import messages
 from django.contrib import messages
 from django.shortcuts import redirect
 from django.shortcuts import redirect

+ 5 - 1
jet/dashboard/dashboard_modules/yandex_metrika.py

@@ -2,7 +2,11 @@
 import datetime
 import datetime
 import json
 import json
 from django import forms
 from django import forms
-from django.core.urlresolvers import reverse
+try:
+    from django.core.urlresolvers import reverse
+except ImportError: # Django 1.11
+    from django.urls import reverse
+
 from django.forms import Widget
 from django.forms import Widget
 from django.utils import formats
 from django.utils import formats
 from django.utils.html import format_html
 from django.utils.html import format_html

+ 5 - 1
jet/dashboard/dashboard_modules/yandex_metrika_views.py

@@ -1,6 +1,10 @@
 from django.conf.urls import url
 from django.conf.urls import url
 from django.contrib import messages
 from django.contrib import messages
-from django.core.urlresolvers import reverse
+try:
+    from django.core.urlresolvers import reverse
+except ImportError: # Django 1.11
+    from django.urls import reverse
+
 from django.http import HttpResponse
 from django.http import HttpResponse
 from django.shortcuts import redirect
 from django.shortcuts import redirect
 from jet.dashboard.dashboard_modules.yandex_metrika import YandexMetrikaClient
 from jet.dashboard.dashboard_modules.yandex_metrika import YandexMetrikaClient

+ 2 - 2
jet/dashboard/modules.py

@@ -4,7 +4,7 @@ from django.contrib.admin.models import LogEntry
 from django.db.models import Q
 from django.db.models import Q
 from django.template.loader import render_to_string
 from django.template.loader import render_to_string
 from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import ugettext_lazy as _
-from jet.utils import get_app_list, LazyDateTimeEncoder
+from jet.utils import get_app_list, LazyDateTimeEncoder, context_to_dict
 import datetime
 import datetime
 
 
 
 
@@ -148,7 +148,7 @@ class DashboardModule(object):
         pass
         pass
 
 
     def get_context_data(self):
     def get_context_data(self):
-        context = self.context
+        context = context_to_dict(self.context)
         context.update({
         context.update({
             'module': self
             'module': self
         })
         })

+ 5 - 1
jet/dashboard/views.py

@@ -1,6 +1,10 @@
 from django.contrib import messages
 from django.contrib import messages
 from django.core.exceptions import ValidationError
 from django.core.exceptions import ValidationError
-from django.core.urlresolvers import reverse
+try:
+    from django.core.urlresolvers import reverse
+except ImportError: # Django 1.11
+    from django.urls import reverse
+
 from django.forms.formsets import formset_factory
 from django.forms.formsets import formset_factory
 from django.http import HttpResponseRedirect
 from django.http import HttpResponseRedirect
 from django.views.decorators.http import require_POST, require_GET
 from django.views.decorators.http import require_POST, require_GET

+ 4 - 1
jet/filters.py

@@ -1,7 +1,10 @@
 from django.contrib.admin import RelatedFieldListFilter
 from django.contrib.admin import RelatedFieldListFilter
 from django.utils.encoding import smart_text
 from django.utils.encoding import smart_text
 from django.utils.html import format_html
 from django.utils.html import format_html
-from django.core.urlresolvers import reverse
+try:
+    from django.core.urlresolvers import reverse
+except ImportError: # Django 1.11
+    from django.urls import reverse
 
 
 try:
 try:
     from django.contrib.admin.utils import get_model_from_relation
     from django.contrib.admin.utils import get_model_from_relation

+ 1 - 1
jet/management/commands/jet_side_menu_items_example.py

@@ -39,7 +39,7 @@ class Command(NoArgsCommand):
         self.stdout.write('JET_SIDE_MENU_ITEMS = [')
         self.stdout.write('JET_SIDE_MENU_ITEMS = [')
 
 
         for app in app_list:
         for app in app_list:
-            self.stdout.write('    {\'app_label\': \'%s\', \'models\': [' % (
+            self.stdout.write('    {\'app_label\': \'%s\', \'items\': [' % (
                 app['app_label']
                 app['app_label']
             ))
             ))
 
 

+ 1 - 1
jet/static/jet/css/_sidebar.scss

@@ -552,7 +552,7 @@
       color: $hover-link-color;
       color: $hover-link-color;
     }
     }
 
 
-    body.menu-pinned & {
+    body.login &, body.menu-pinned & {
       display: none;
       display: none;
     }
     }
 
 

Fichier diff supprimé car celui-ci est trop grand
+ 0 - 0
jet/static/jet/css/themes/default/base.css


Fichier diff supprimé car celui-ci est trop grand
+ 0 - 0
jet/static/jet/css/themes/default/base.css.map


Fichier diff supprimé car celui-ci est trop grand
+ 0 - 0
jet/static/jet/css/themes/green/base.css


Fichier diff supprimé car celui-ci est trop grand
+ 0 - 0
jet/static/jet/css/themes/green/base.css.map


Fichier diff supprimé car celui-ci est trop grand
+ 0 - 0
jet/static/jet/css/themes/light-blue/base.css


Fichier diff supprimé car celui-ci est trop grand
+ 0 - 0
jet/static/jet/css/themes/light-blue/base.css.map


Fichier diff supprimé car celui-ci est trop grand
+ 0 - 0
jet/static/jet/css/themes/light-gray/base.css


Fichier diff supprimé car celui-ci est trop grand
+ 0 - 0
jet/static/jet/css/themes/light-gray/base.css.map


Fichier diff supprimé car celui-ci est trop grand
+ 0 - 0
jet/static/jet/css/themes/light-green/base.css


Fichier diff supprimé car celui-ci est trop grand
+ 0 - 0
jet/static/jet/css/themes/light-green/base.css.map


Fichier diff supprimé car celui-ci est trop grand
+ 0 - 0
jet/static/jet/css/themes/light-violet/base.css


Fichier diff supprimé car celui-ci est trop grand
+ 0 - 0
jet/static/jet/css/themes/light-violet/base.css.map


Fichier diff supprimé car celui-ci est trop grand
+ 0 - 0
jet/static/jet/css/vendor.css


+ 3 - 3
jet/templates/admin/base.html

@@ -36,7 +36,7 @@
 </head>
 </head>
 {% load i18n %}
 {% load i18n %}
 
 
-<body class="{% if request.COOKIES.sidebar_pinned == 'true' %}menu-pinned {% endif %}{% if is_popup %}popup {% endif %}{% block bodyclass %}{% endblock %}"
+<body class="{% if request.COOKIES.sidebar_pinned != 'false' %}menu-pinned {% endif %}{% if is_popup %}popup {% endif %}{% block bodyclass %}{% endblock %}"
   data-admin-utc-offset="{% now "Z" %}">
   data-admin-utc-offset="{% now "Z" %}">
 
 
 <!-- Container -->
 <!-- Container -->
@@ -202,7 +202,7 @@
                                             {{ app.label }}
                                             {{ app.label }}
                                         </a>
                                         </a>
                                     </div>
                                     </div>
-                                    {% for model in app.models %}
+                                    {% for model in app.items %}
                                         {% if model.has_perms %}
                                         {% if model.has_perms %}
                                             <div>
                                             <div>
                                                 <a{% if model.url %} href="{{ model.url }}"{% endif %} class="sidebar-link"{% if model.url_blank %} target="_blank"{% endif %}>
                                                 <a{% if model.url %} href="{{ model.url }}"{% endif %} class="sidebar-link"{% if model.url_blank %} target="_blank"{% endif %}>
@@ -346,7 +346,7 @@
                                             </li>
                                             </li>
                                         {% endif %}
                                         {% endif %}
 
 
-                                        {% for model in app.models %}
+                                        {% for model in app.items %}
                                             {% if model.has_perms %}
                                             {% if model.has_perms %}
                                                 <li class="sidebar-popup-list-item{% if model.name %} model-{{ model.name }}{% endif %}{{ model.current|yesno:" current," }}">
                                                 <li class="sidebar-popup-list-item{% if model.name %} model-{{ model.name }}{% endif %}{{ model.current|yesno:" current," }}">
                                                     <a{% if model.url %} href="{{ model.url }}"{% endif %} class="sidebar-popup-list-item-link"{% if model.url_blank %} target="_blank"{% endif %}>
                                                     <a{% if model.url %} href="{{ model.url }}"{% endif %} class="sidebar-popup-list-item-link"{% if model.url_blank %} target="_blank"{% endif %}>

+ 6 - 3
jet/templatetags/jet_tags.py

@@ -2,7 +2,11 @@ from __future__ import unicode_literals
 import json
 import json
 import os
 import os
 from django import template
 from django import template
-from django.core.urlresolvers import reverse
+try:
+    from django.core.urlresolvers import reverse
+except ImportError: # Django 1.11
+    from django.urls import reverse
+
 from django.forms import CheckboxInput, ModelChoiceField, Select, ModelMultipleChoiceField, SelectMultiple
 from django.forms import CheckboxInput, ModelChoiceField, Select, ModelMultipleChoiceField, SelectMultiple
 from django.contrib.admin.widgets import RelatedFieldWidgetWrapper
 from django.contrib.admin.widgets import RelatedFieldWidgetWrapper
 from django.utils.formats import get_format
 from django.utils.formats import get_format
@@ -73,8 +77,7 @@ def jet_select2_lookups(field):
                 'data-ajax--url': reverse('jet:model_lookup')
                 'data-ajax--url': reverse('jet:model_lookup')
             }
             }
 
 
-            form = field.form
-            initial_value = form.data.get(field.name) if form.data != {} else form.initial.get(field.name)
+            initial_value = field.value()
 
 
             if hasattr(field, 'field') and isinstance(field.field, ModelMultipleChoiceField):
             if hasattr(field, 'field') and isinstance(field.field, ModelMultipleChoiceField):
                 if initial_value:
                 if initial_value:

+ 5 - 1
jet/tests/test_dashboard.py

@@ -1,5 +1,9 @@
 from django.contrib.auth.models import User
 from django.contrib.auth.models import User
-from django.core.urlresolvers import reverse
+try:
+    from django.core.urlresolvers import reverse
+except ImportError: # Django 1.11
+    from django.urls import reverse
+
 from django.test import TestCase, Client
 from django.test import TestCase, Client
 from jet.dashboard.dashboard import Dashboard
 from jet.dashboard.dashboard import Dashboard
 from jet.dashboard.modules import LinkList, RecentActions
 from jet.dashboard.modules import LinkList, RecentActions

+ 10 - 6
jet/tests/test_tags.py

@@ -1,7 +1,11 @@
 from django import forms
 from django import forms
-from django.core.urlresolvers import reverse
+try:
+    from django.core.urlresolvers import reverse
+except ImportError: # Django 1.11
+    from django.urls import reverse
+
 from django.test import TestCase
 from django.test import TestCase
-from jet.templatetags.jet_tags import jet_select2_lookups, jet_next_object_url, jet_previous_object_url
+from jet.templatetags.jet_tags import jet_select2_lookups, jet_next_object, jet_previous_object
 from jet.tests.models import TestModel, SearchableTestModel
 from jet.tests.models import TestModel, SearchableTestModel
 from django.test.client import RequestFactory
 from django.test.client import RequestFactory
 
 
@@ -72,7 +76,7 @@ class TagsTestCase(TestCase):
             'request': RequestFactory().get(expected_url),
             'request': RequestFactory().get(expected_url),
         }
         }
 
 
-        actual_url = jet_next_object_url(context)
+        actual_url = jet_next_object(context)['url']
 
 
         self.assertEqual(actual_url, expected_url)
         self.assertEqual(actual_url, expected_url)
 
 
@@ -92,7 +96,7 @@ class TagsTestCase(TestCase):
             'request': RequestFactory().get(changelist_url),
             'request': RequestFactory().get(changelist_url),
         }
         }
 
 
-        actual_url = jet_previous_object_url(context)
-        expected_url = None
+        previous_object = jet_previous_object(context)
+        expected_object = None
 
 
-        self.assertEqual(actual_url, expected_url)
+        self.assertEqual(previous_object, expected_object)

+ 5 - 1
jet/tests/test_views.py

@@ -1,6 +1,10 @@
 import json
 import json
 from django.contrib.auth.models import User
 from django.contrib.auth.models import User
-from django.core.urlresolvers import reverse
+try:
+    from django.core.urlresolvers import reverse
+except ImportError: # Django 1.11
+    from django.urls import reverse
+
 from django.test import TestCase, Client
 from django.test import TestCase, Client
 from jet.dashboard.modules import LinkList
 from jet.dashboard.modules import LinkList
 from jet.models import Bookmark
 from jet.models import Bookmark

+ 32 - 11
jet/utils.py

@@ -1,5 +1,6 @@
 import datetime
 import datetime
 import json
 import json
+from django.template import Context
 from django.utils import translation
 from django.utils import translation
 from jet import settings
 from jet import settings
 from jet.models import PinnedApplication
 from jet.models import PinnedApplication
@@ -13,7 +14,11 @@ except ImportError:
         pass
         pass
 from django.core.serializers.json import DjangoJSONEncoder
 from django.core.serializers.json import DjangoJSONEncoder
 from django.http import HttpResponse
 from django.http import HttpResponse
-from django.core.urlresolvers import reverse, resolve, NoReverseMatch
+try:
+    from django.core.urlresolvers import reverse, resolve, NoReverseMatch
+except ImportError: # Django 1.11
+    from django.urls import reverse, resolve, NoReverseMatch
+
 from django.contrib.admin import AdminSite
 from django.contrib.admin import AdminSite
 from django.utils.encoding import smart_text
 from django.utils.encoding import smart_text
 from django.utils.text import capfirst
 from django.utils.text import capfirst
@@ -21,11 +26,14 @@ from django.contrib import messages
 from django.utils.encoding import force_text
 from django.utils.encoding import force_text
 from django.utils.functional import Promise
 from django.utils.functional import Promise
 from django.contrib.admin.options import IncorrectLookupParameters
 from django.contrib.admin.options import IncorrectLookupParameters
-from django.core import urlresolvers
 from django.contrib import admin
 from django.contrib import admin
 from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import ugettext_lazy as _
 from django.utils.text import slugify
 from django.utils.text import slugify
-from collections import OrderedDict
+
+try:
+    from collections import OrderedDict
+except ImportError:
+    from ordereddict import OrderedDict  # Python 2.6
 
 
 
 
 class JsonResponse(HttpResponse):
 class JsonResponse(HttpResponse):
@@ -173,7 +181,7 @@ def get_model_queryset(admin_site, model, request, preserved_filters=None):
     model_admin = admin_site._registry.get(model)
     model_admin = admin_site._registry.get(model)
 
 
     try:
     try:
-        changelist_url = urlresolvers.reverse('%s:%s_%s_changelist' % (
+        changelist_url = reverse('%s:%s_%s_changelist' % (
             admin_site.name,
             admin_site.name,
             model._meta.app_label,
             model._meta.app_label,
             model._meta.model_name
             model._meta.model_name
@@ -349,8 +357,8 @@ def get_menu_items(context):
             if 'label' in data:
             if 'label' in data:
                 item['label'] = data['label']
                 item['label'] = data['label']
 
 
-            if 'models' in data:
-                item['models'] = list(map(lambda x: get_menu_item_app_model(app_label, x), data['models']))
+            if 'items' in data:
+                item['items'] = list(map(lambda x: get_menu_item_app_model(app_label, x), data['items']))
 
 
             if 'url' in data:
             if 'url' in data:
                 item['url'] = get_menu_item_url(data['url'], original_app_list)
                 item['url'] = get_menu_item_url(data['url'], original_app_list)
@@ -382,7 +390,7 @@ def get_menu_items(context):
 
 
                 models_dict[app_label][model['object_name']] = model
                 models_dict[app_label][model['object_name']] = model
 
 
-            app['models'] = []
+            app['items'] = []
 
 
         app_list = []
         app_list = []
 
 
@@ -398,21 +406,24 @@ def get_menu_items(context):
 
 
                 for model_label in models:
                 for model_label in models:
                     if model_label == '__all__':
                     if model_label == '__all__':
-                        app['models'] = models_dict[app_label].values()
+                        app['items'] = models_dict[app_label].values()
                         break
                         break
                     elif model_label in models_dict[app_label]:
                     elif model_label in models_dict[app_label]:
                         model = models_dict[app_label][model_label]
                         model = models_dict[app_label][model_label]
-                        app['models'].append(model)
+                        app['items'].append(model)
 
 
                 app_list.append(app)
                 app_list.append(app)
     else:
     else:
-        app_list = original_app_list.values()
+        def map_item(item):
+            item['items'] = item['models']
+            return item
+        app_list = map(map_item, original_app_list.values())
 
 
     current_found = False
     current_found = False
 
 
     for app in app_list:
     for app in app_list:
         if not current_found:
         if not current_found:
-            for model in app['models']:
+            for model in app['items']:
                 if not current_found and model.get('url') and context['request'].path.startswith(model['url']):
                 if not current_found and model.get('url') and context['request'].path.startswith(model['url']):
                     model['current'] = True
                     model['current'] = True
                     current_found = True
                     current_found = True
@@ -426,3 +437,13 @@ def get_menu_items(context):
                 app['current'] = False
                 app['current'] = False
 
 
     return app_list
     return app_list
+
+
+def context_to_dict(context):
+    if isinstance(context, Context):
+        flat = {}
+        for d in context.dicts:
+            flat.update(d)
+        context = flat
+
+    return context

+ 7 - 0
setup.py

@@ -13,10 +13,17 @@ def read(fname):
 
 
 def get_install_requires():
 def get_install_requires():
     install_requires = ['Django']
     install_requires = ['Django']
+
     try:
     try:
         import importlib
         import importlib
     except ImportError:
     except ImportError:
         install_requires.append('importlib')
         install_requires.append('importlib')
+
+    try:
+        from collections import OrderedDict
+    except ImportError:
+        install_requires.append('ordereddict')
+
     return install_requires
     return install_requires
 
 
 setup(
 setup(

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff