浏览代码

Drop support for Django 2.2 and Python 3.6

master
Samir Shah 3 年前
父节点
当前提交
f53bc49507

+ 3
- 3
.github/workflows/test.yml 查看文件

15
     strategy:
15
     strategy:
16
       fail-fast: true
16
       fail-fast: true
17
       matrix:
17
       matrix:
18
-        python-version: [3.6, 3.7, 3.8, 3.9]
19
-        django-version: [2.2, 3.1, 3.2]
18
+        python-version: [3.7, 3.8, 3.9]
19
+        django-version: [3.1, 3.2]
20
     services:
20
     services:
21
       postgres:
21
       postgres:
22
         image: postgres:10
22
         image: postgres:10
59
     - name: Set up Python ${{ matrix.python-version }}
59
     - name: Set up Python ${{ matrix.python-version }}
60
       uses: actions/setup-python@v2
60
       uses: actions/setup-python@v2
61
       with:
61
       with:
62
-        python-version: 3.7
62
+        python-version: 3.8
63
     - name: Install dependencies
63
     - name: Install dependencies
64
       run: |
64
       run: |
65
         python -m pip install --upgrade pip
65
         python -m pip install --upgrade pip

+ 2
- 2
Dockerfile 查看文件

1
-FROM python:3.7
1
+FROM python:3.8
2
 ENV PYTHONUNBUFFERED 1
2
 ENV PYTHONUNBUFFERED 1
3
 
3
 
4
-RUN curl -sL https://deb.nodesource.com/setup_12.x | bash -
4
+RUN curl -sL https://deb.nodesource.com/setup_14.x | bash -
5
 RUN apt-get install -y nodejs
5
 RUN apt-get install -y nodejs
6
 
6
 
7
 COPY ./requirements.txt /requirements.txt
7
 COPY ./requirements.txt /requirements.txt

+ 1
- 1
docs/source/internals/contributing/running-tests.rst 查看文件

8
 You'll need:
8
 You'll need:
9
 
9
 
10
 - A running SQL server (PostgreSQL, or SQLite with `--sqlite` parameters)
10
 - A running SQL server (PostgreSQL, or SQLite with `--sqlite` parameters)
11
-- python3.6 or python3.7
11
+- python3.7 or higher.
12
 
12
 
13
 Running tests
13
 Running tests
14
 -------------
14
 -------------

+ 8
- 9
docs/source/ref/settings.rst 查看文件

99
 The default is::
99
 The default is::
100
 
100
 
101
     OSCAR_SEARCH_FACETS = {
101
     OSCAR_SEARCH_FACETS = {
102
-        'fields': OrderedDict([
103
-            ('product_class', {'name': _('Type'), 'field': 'product_class'}),
104
-            ('rating', {'name': _('Rating'), 'field': 'rating'}),
105
-        ]),
106
-        'queries': OrderedDict([
107
-            ('price_range',
108
-             {
102
+        'fields': {
103
+            'product_class': {'name': _('Type'), 'field': 'product_class'},
104
+            'rating': {'name': _('Rating'), 'field': 'rating'},
105
+        },
106
+        'queries': {
107
+            'price_range': {
109
                  'name': _('Price range'),
108
                  'name': _('Price range'),
110
                  'field': 'price',
109
                  'field': 'price',
111
                  'queries': [
110
                  'queries': [
116
                      (_('40 to 60'), '[40 TO 60]'),
115
                      (_('40 to 60'), '[40 TO 60]'),
117
                      (_('60+'), '[60 TO *]'),
116
                      (_('60+'), '[60 TO *]'),
118
                  ]
117
                  ]
119
-             }),
120
-        ]),
118
+             },
119
+        },
121
     }
120
     }
122
 
121
 
123
 ``OSCAR_PRODUCT_SEARCH_HANDLER``
122
 ``OSCAR_PRODUCT_SEARCH_HANDLER``

+ 10
- 0
docs/source/releases/v3.2.rst 查看文件

14
 Compatibility
14
 Compatibility
15
 ~~~~~~~~~~~~~
15
 ~~~~~~~~~~~~~
16
 
16
 
17
+Oscar 3.2 is compatible with Django 3.1 and Django 3.2 and Python versions 3.7 to 3.9.
18
+
19
+Support for Django 2.2 has been dropped. Support for Python 3.6 has been dropped.
17
 
20
 
18
 .. _new_in_3.2:
21
 .. _new_in_3.2:
19
 
22
 
46
 
49
 
47
 
50
 
48
 Javascript and CSS dependencies:
51
 Javascript and CSS dependencies:
52
+
53
+
54
+Deprecated features
55
+~~~~~~~~~~~~~~~~~~~
56
+
57
+- The ``annotate_form_field`` template tag is deprecated. It's functionality of annotating form fields with
58
+  their widget type is now built in to Django.

+ 2
- 3
setup.py 查看文件

18
 from oscar import get_version  # noqa isort:skip
18
 from oscar import get_version  # noqa isort:skip
19
 
19
 
20
 install_requires = [
20
 install_requires = [
21
-    'django>=2.2,<3.3',
21
+    'django>=3.1,<3.3',
22
     # PIL is required for image fields, Pillow is the "friendly" PIL fork
22
     # PIL is required for image fields, Pillow is the "friendly" PIL fork
23
     'pillow>=6.0',
23
     'pillow>=6.0',
24
     # We use the ModelFormSetView from django-extra-views for the basket page
24
     # We use the ModelFormSetView from django-extra-views for the basket page
87
     package_dir={'': 'src'},
87
     package_dir={'': 'src'},
88
     packages=find_packages('src'),
88
     packages=find_packages('src'),
89
     include_package_data=True,
89
     include_package_data=True,
90
+    python_requires='>=3.7',
90
     install_requires=install_requires,
91
     install_requires=install_requires,
91
     extras_require={
92
     extras_require={
92
         'docs': docs_requires,
93
         'docs': docs_requires,
98
         'Development Status :: 5 - Production/Stable',
99
         'Development Status :: 5 - Production/Stable',
99
         'Environment :: Web Environment',
100
         'Environment :: Web Environment',
100
         'Framework :: Django',
101
         'Framework :: Django',
101
-        'Framework :: Django :: 2.2',
102
         'Framework :: Django :: 3.1',
102
         'Framework :: Django :: 3.1',
103
         'Framework :: Django :: 3.2',
103
         'Framework :: Django :: 3.2',
104
         'Intended Audience :: Developers',
104
         'Intended Audience :: Developers',
106
         'Operating System :: Unix',
106
         'Operating System :: Unix',
107
         'Programming Language :: Python',
107
         'Programming Language :: Python',
108
         'Programming Language :: Python :: 3',
108
         'Programming Language :: Python :: 3',
109
-        'Programming Language :: Python :: 3.6',
110
         'Programming Language :: Python :: 3.7',
109
         'Programming Language :: Python :: 3.7',
111
         'Programming Language :: Python :: 3.8',
110
         'Programming Language :: Python :: 3.8',
112
         'Programming Language :: Python :: 3.9',
111
         'Programming Language :: Python :: 3.9',

+ 1
- 1
src/oscar/apps/basket/views.py 查看文件

5
 from django.shortcuts import redirect
5
 from django.shortcuts import redirect
6
 from django.template.loader import render_to_string
6
 from django.template.loader import render_to_string
7
 from django.urls import reverse
7
 from django.urls import reverse
8
+from django.utils.http import url_has_allowed_host_and_scheme
8
 from django.utils.translation import gettext_lazy as _
9
 from django.utils.translation import gettext_lazy as _
9
 from django.views.generic import FormView, View
10
 from django.views.generic import FormView, View
10
 from extra_views import ModelFormSetView
11
 from extra_views import ModelFormSetView
12
 from oscar.apps.basket.signals import (
13
 from oscar.apps.basket.signals import (
13
     basket_addition, voucher_addition, voucher_removal)
14
     basket_addition, voucher_addition, voucher_removal)
14
 from oscar.core import ajax
15
 from oscar.core import ajax
15
-from oscar.core.compat import url_has_allowed_host_and_scheme
16
 from oscar.core.loading import get_class, get_classes, get_model
16
 from oscar.core.loading import get_class, get_classes, get_model
17
 from oscar.core.utils import is_ajax, redirect_to_referrer, safe_referrer
17
 from oscar.core.utils import is_ajax, redirect_to_referrer, safe_referrer
18
 
18
 

+ 2
- 2
src/oscar/apps/customer/forms.py 查看文件

9
 from django.contrib.sites.shortcuts import get_current_site
9
 from django.contrib.sites.shortcuts import get_current_site
10
 from django.core.exceptions import ValidationError
10
 from django.core.exceptions import ValidationError
11
 from django.utils.crypto import get_random_string
11
 from django.utils.crypto import get_random_string
12
+from django.utils.http import url_has_allowed_host_and_scheme
12
 from django.utils.translation import gettext_lazy as _
13
 from django.utils.translation import gettext_lazy as _
13
 from django.utils.translation import pgettext_lazy
14
 from django.utils.translation import pgettext_lazy
14
 
15
 
15
 from oscar.apps.customer.utils import get_password_reset_url, normalise_email
16
 from oscar.apps.customer.utils import get_password_reset_url, normalise_email
16
-from oscar.core.compat import (
17
-    existing_user_fields, get_user_model, url_has_allowed_host_and_scheme)
17
+from oscar.core.compat import existing_user_fields, get_user_model
18
 from oscar.core.loading import get_class, get_model, get_profile_class
18
 from oscar.core.loading import get_class, get_model, get_profile_class
19
 from oscar.core.utils import datetime_combine
19
 from oscar.core.utils import datetime_combine
20
 from oscar.forms import widgets
20
 from oscar.forms import widgets

+ 12
- 14
src/oscar/apps/dashboard/orders/views.py 查看文件

1
 import datetime
1
 import datetime
2
-from collections import OrderedDict
3
 from decimal import Decimal as D
2
 from decimal import Decimal as D
4
 from decimal import InvalidOperation
3
 from decimal import InvalidOperation
5
 
4
 
117
     form_class = OrderSearchForm
116
     form_class = OrderSearchForm
118
     paginate_by = settings.OSCAR_DASHBOARD_ITEMS_PER_PAGE
117
     paginate_by = settings.OSCAR_DASHBOARD_ITEMS_PER_PAGE
119
     actions = ('download_selected_orders', 'change_order_statuses')
118
     actions = ('download_selected_orders', 'change_order_statuses')
120
-    CSV_COLUMNS = (
121
-        ('number', _('Order number')),
122
-        ('value', _('Order value')),
123
-        ('date', _('Date of purchase')),
124
-        ('num_items', _('Number of items')),
125
-        ('status', _('Order status')),
126
-        ('customer', _('Customer email address')),
127
-        ('shipping_address_name', _('Deliver to name')),
128
-        ('billing_address_name', _('Bill to name')),
129
-    )
119
+    CSV_COLUMNS = {
120
+        'number', _('Order number'),
121
+        'value', _('Order value'),
122
+        'date', _('Date of purchase'),
123
+        'num_items', _('Number of items'),
124
+        'status', _('Order status'),
125
+        'customer', _('Customer email address'),
126
+        'shipping_address_name', _('Deliver to name'),
127
+        'billing_address_name', _('Bill to name'),
128
+    }
130
 
129
 
131
     def dispatch(self, request, *args, **kwargs):
130
     def dispatch(self, request, *args, **kwargs):
132
         # base_queryset is equal to all orders the user is allowed to access
131
         # base_queryset is equal to all orders the user is allowed to access
382
             % self.get_download_filename(request)
381
             % self.get_download_filename(request)
383
         writer = UnicodeCSVWriter(open_file=response)
382
         writer = UnicodeCSVWriter(open_file=response)
384
 
383
 
385
-        ordered_columns = OrderedDict(self.CSV_COLUMNS)
386
-        writer.writerow(ordered_columns.values())
384
+        writer.writerow(self.CSV_COLUMNS.values())
387
         for order in orders:
385
         for order in orders:
388
             row_values = self.get_row_values(order)
386
             row_values = self.get_row_values(order)
389
-            writer.writerow([row_values.get(column, "") for column in ordered_columns])
387
+            writer.writerow([row_values.get(column, "") for column in self.CSV_COLUMNS])
390
         return response
388
         return response
391
 
389
 
392
     def change_order_statuses(self, request, orders):
390
     def change_order_statuses(self, request, orders):

+ 2
- 3
src/oscar/apps/order/abstract_models.py 查看文件

1
 import logging
1
 import logging
2
-from collections import OrderedDict
3
 from decimal import Decimal as D
2
 from decimal import Decimal as D
4
 
3
 
5
 from django.conf import settings
4
 from django.conf import settings
260
             return ''
259
             return ''
261
 
260
 
262
         # Collect all events by event-type
261
         # Collect all events by event-type
263
-        event_map = OrderedDict()
262
+        event_map = {}
264
         for event in events:
263
         for event in events:
265
             event_name = event.event_type.name
264
             event_name = event.event_type.name
266
             if event_name not in event_map:
265
             if event_name not in event_map:
719
         """
718
         """
720
         Returns a dict of shipping events that this line has been through
719
         Returns a dict of shipping events that this line has been through
721
         """
720
         """
722
-        status_map = OrderedDict()
721
+        status_map = {}
723
         for event in self.shipping_events.all():
722
         for event in self.shipping_events.all():
724
             event_type = event.event_type
723
             event_type = event.event_type
725
             event_name = event_type.name
724
             event_name = event_type.name

+ 1
- 3
src/oscar/apps/search/facets.py 查看文件

1
-from collections import OrderedDict
2
-
3
 from django.conf import settings
1
 from django.conf import settings
4
 from haystack.query import SearchQuerySet
2
 from haystack.query import SearchQuerySet
5
 from purl import URL
3
 from purl import URL
27
         self.facet_counts = facet_counts
25
         self.facet_counts = facet_counts
28
 
26
 
29
     def facet_data(self):
27
     def facet_data(self):
30
-        facet_data = OrderedDict()
28
+        facet_data = {}
31
         # Haystack can return an empty dict for facet_counts when e.g. Solr
29
         # Haystack can return an empty dict for facet_counts when e.g. Solr
32
         # isn't running. Skip facet munging in that case.
30
         # isn't running. Skip facet munging in that case.
33
         if self.facet_counts:
31
         if self.facet_counts:

+ 0
- 26
src/oscar/core/compat.py 查看文件

1
 import csv
1
 import csv
2
-import re
3
 
2
 
4
-from django import template
5
 from django.conf import settings
3
 from django.conf import settings
6
 from django.contrib.auth.models import User
4
 from django.contrib.auth.models import User
7
 from django.core.exceptions import ImproperlyConfigured
5
 from django.core.exceptions import ImproperlyConfigured
17
                                " 'app_label.model_name'")
15
                                " 'app_label.model_name'")
18
 
16
 
19
 
17
 
20
-# Backward-compatible import for url_has_allowed_host_and_scheme.
21
-try:
22
-    # Django 3.0 and above
23
-    from django.utils.http import url_has_allowed_host_and_scheme  # noqa F401
24
-except ImportError:
25
-    from django.utils.http import is_safe_url as url_has_allowed_host_and_scheme  # noqa F401 isort:skip
26
-
27
-
28
 def get_user_model():
18
 def get_user_model():
29
     """
19
     """
30
     Return the User model. Doesn't require the app cache to be fully
20
     Return the User model. Doesn't require the app cache to be fully
129
     def writerows(self, rows):
119
     def writerows(self, rows):
130
         for row in rows:
120
         for row in rows:
131
             self.writerow(row)
121
             self.writerow(row)
132
-
133
-
134
-class FormFieldNode(template.Node):
135
-    """"
136
-    Add the widget type to a BoundField. Until 3.1, Django did not make this available by default.
137
-
138
-    Used by `oscar.templatetags.form_tags.annotate_form_field`
139
-    """
140
-    def __init__(self, field_str):
141
-        self.field = template.Variable(field_str)
142
-
143
-    def render(self, context):
144
-        field = self.field.resolve(context)
145
-        if not hasattr(field, 'widget_type') and hasattr(field, 'field'):
146
-            field.widget_type = re.sub(r'widget$|input$', '', field.field.widget.__class__.__name__.lower())
147
-        return ''

+ 1
- 2
src/oscar/core/utils.py 查看文件

8
 from django.conf import settings
8
 from django.conf import settings
9
 from django.shortcuts import redirect, resolve_url
9
 from django.shortcuts import redirect, resolve_url
10
 from django.template.defaultfilters import date as date_filter
10
 from django.template.defaultfilters import date as date_filter
11
+from django.utils.http import url_has_allowed_host_and_scheme
11
 from django.utils.module_loading import import_string
12
 from django.utils.module_loading import import_string
12
 from django.utils.text import slugify as django_slugify
13
 from django.utils.text import slugify as django_slugify
13
 from django.utils.timezone import get_current_timezone, is_naive, make_aware
14
 from django.utils.timezone import get_current_timezone, is_naive, make_aware
14
 from django.utils.translation import get_language, to_locale
15
 from django.utils.translation import get_language, to_locale
15
 
16
 
16
-from oscar.core.compat import url_has_allowed_host_and_scheme
17
-
18
 SLUGIFY_RE = re.compile(r'[^\w\s-]', re.UNICODE)
17
 SLUGIFY_RE = re.compile(r'[^\w\s-]', re.UNICODE)
19
 
18
 
20
 
19
 

+ 18
- 21
src/oscar/defaults.py 查看文件

1
-from collections import OrderedDict
2
-
3
 from django.urls import reverse_lazy
1
 from django.urls import reverse_lazy
4
 from django.utils.translation import gettext_lazy as _
2
 from django.utils.translation import gettext_lazy as _
5
 
3
 
216
 
214
 
217
 # Search facets
215
 # Search facets
218
 OSCAR_SEARCH_FACETS = {
216
 OSCAR_SEARCH_FACETS = {
219
-    'fields': OrderedDict([
217
+    'fields': {
220
         # The key for these dicts will be used when passing facet data
218
         # The key for these dicts will be used when passing facet data
221
         # to the template. Same for the 'queries' dict below.
219
         # to the template. Same for the 'queries' dict below.
222
-        ('product_class', {'name': _('Type'), 'field': 'product_class'}),
223
-        ('rating', {'name': _('Rating'), 'field': 'rating'}),
220
+        'product_class': {'name': _('Type'), 'field': 'product_class'},
221
+        'rating': {'name': _('Rating'), 'field': 'rating'},
224
         # You can specify an 'options' element that will be passed to the
222
         # You can specify an 'options' element that will be passed to the
225
         # SearchQuerySet.facet() call.
223
         # SearchQuerySet.facet() call.
226
         # For instance, with Elasticsearch backend, 'options': {'order': 'term'}
224
         # For instance, with Elasticsearch backend, 'options': {'order': 'term'}
230
         # items without a specific facet:
228
         # items without a specific facet:
231
         # http://wiki.apache.org/solr/SimpleFacetParameters#facet.method
229
         # http://wiki.apache.org/solr/SimpleFacetParameters#facet.method
232
         # 'options': {'missing': 'true'}
230
         # 'options': {'missing': 'true'}
233
-    ]),
234
-    'queries': OrderedDict([
235
-        ('price_range',
236
-         {
237
-             'name': _('Price range'),
238
-             'field': 'price',
239
-             'queries': [
240
-                 # This is a list of (name, query) tuples where the name will
241
-                 # be displayed on the front-end.
242
-                 (_('0 to 20'), '[0 TO 20]'),
243
-                 (_('20 to 40'), '[20 TO 40]'),
244
-                 (_('40 to 60'), '[40 TO 60]'),
245
-                 (_('60+'), '[60 TO *]'),
246
-             ]
247
-         }),
248
-    ]),
231
+    },
232
+    'queries': {
233
+        'price_range': {
234
+            'name': _('Price range'),
235
+            'field': 'price',
236
+            'queries': [
237
+                # This is a list of (name, query) tuples where the name will
238
+                # be displayed on the front-end.
239
+                (_('0 to 20'), '[0 TO 20]'),
240
+                (_('20 to 40'), '[20 TO 40]'),
241
+                (_('40 to 60'), '[40 TO 60]'),
242
+                (_('60+'), '[60 TO *]'),
243
+            ]
244
+        },
245
+    },
249
 }
246
 }
250
 
247
 
251
 OSCAR_PRODUCT_SEARCH_HANDLER = None
248
 OSCAR_PRODUCT_SEARCH_HANDLER = None

+ 0
- 1
src/oscar/templates/oscar/dashboard/catalogue/product_update.html 查看文件

1
 {% extends 'oscar/dashboard/layout.html' %}
1
 {% extends 'oscar/dashboard/layout.html' %}
2
-{% load form_tags %}
3
 {% load i18n %}
2
 {% load i18n %}
4
 
3
 
5
 {% block body_class %}{{ block.super }} create-page catalogue{% endblock %}
4
 {% block body_class %}{{ block.super }} create-page catalogue{% endblock %}

+ 0
- 2
src/oscar/templates/oscar/dashboard/partials/form_field.html 查看文件

1
-{% load form_tags %}
2
 {% load widget_tweaks %}
1
 {% load widget_tweaks %}
3
 
2
 
4
 {% if field.is_hidden %}
3
 {% if field.is_hidden %}
8
         Make the field widget type available to templates so we can mark-up
7
         Make the field widget type available to templates so we can mark-up
9
         checkbox and radio inputs differently to other widgets.
8
         checkbox and radio inputs differently to other widgets.
10
     {% endcomment %}
9
     {% endcomment %}
11
-    {% annotate_form_field field %}
12
 
10
 
13
     {% block control_group %}
11
     {% block control_group %}
14
         <div class="form-group{% if style == 'horizontal' %} row{% endif %}{% if field.errors %} error{% endif %}">
12
         <div class="form-group{% if style == 'horizontal' %} row{% endif %}{% if field.errors %} error{% endif %}">

+ 0
- 2
src/oscar/templates/oscar/partials/form_field.html 查看文件

1
-{% load form_tags %}
2
 {% load widget_tweaks %}
1
 {% load widget_tweaks %}
3
 
2
 
4
 {% if field.is_hidden %}
3
 {% if field.is_hidden %}
8
         Make the field widget type available to templates so we can mark-up
7
         Make the field widget type available to templates so we can mark-up
9
         checkbox and radio inputs differently to other widgets.
8
         checkbox and radio inputs differently to other widgets.
10
     {% endcomment %}
9
     {% endcomment %}
11
-    {% annotate_form_field field %}
12
 
10
 
13
     {% block control_group %}
11
     {% block control_group %}
14
         <div class="form-group{% if style == "horizontal" %} row{% endif %}">
12
         <div class="form-group{% if style == "horizontal" %} row{% endif %}">

+ 2
- 2
src/oscar/templatetags/category_tags.py 查看文件

67
         yield self
67
         yield self
68
 
68
 
69
 
69
 
70
-@register.simple_tag(name="category_tree")   # noqa: C901 too complex
71
-def get_annotated_list(depth=None, parent=None):
70
+@register.simple_tag(name="category_tree")
71
+def get_annotated_list(depth=None, parent=None):    # noqa: C901 too complex
72
     """
72
     """
73
     Gets an annotated list from a tree branch.
73
     Gets an annotated list from a tree branch.
74
 
74
 

+ 10
- 12
src/oscar/templatetags/form_tags.py 查看文件

1
-import django
1
+import warnings
2
+
2
 from django import template
3
 from django import template
3
 from django.template.base import TextNode
4
 from django.template.base import TextNode
4
 
5
 
5
-from oscar.core.compat import FormFieldNode
6
+from oscar.utils.deprecation import RemovedInOscar32Warning
6
 
7
 
7
 register = template.Library()
8
 register = template.Library()
8
 
9
 
10
 @register.tag
11
 @register.tag
11
 def annotate_form_field(parser, token):
12
 def annotate_form_field(parser, token):
12
     """
13
     """
13
-    Set an attribute on a form field with the widget type
14
-
15
-    This means templates can use the widget type to render things differently
16
-    if they want to. Until 3.1, Django did not make this available by default.
14
+    Used to set an attribute on a form field with the widget type. This is now
15
+    done by Django itself.
17
     """
16
     """
18
-    args = token.split_contents()
19
-    if len(args) < 2:
20
-        raise template.TemplateSyntaxError(
21
-            "annotate_form_field tag requires a form field to be passed")
22
-    if django.VERSION < (3, 1):
23
-        return FormFieldNode(args[1])
17
+    warnings.warn(
18
+        "The annotate_form_field template tag is deprecated and will be removed in the next version of django-oscar",
19
+        RemovedInOscar32Warning,
20
+        stacklevel=2
21
+    )
24
     return TextNode('')
22
     return TextNode('')

+ 2
- 2
src/oscar/templatetags/history_tags.py 查看文件

26
             'request': request}
26
             'request': request}
27
 
27
 
28
 
28
 
29
-@register.simple_tag(takes_context=True)  # noqa (too complex (11))
30
-def get_back_button(context):
29
+@register.simple_tag(takes_context=True)
30
+def get_back_button(context):   # noqa (too complex (11))
31
     """
31
     """
32
     Show back button, custom title available for different urls, for
32
     Show back button, custom title available for different urls, for
33
     example 'Back to search results', no back button if user came from other
33
     example 'Back to search results', no back button if user came from other

+ 17
- 20
tests/integration/search/test_munger.py 查看文件

1
-from collections import OrderedDict
2
-
3
 from django.test import TestCase
1
 from django.test import TestCase
4
 from django.test.utils import override_settings
2
 from django.test.utils import override_settings
5
 from django.utils.translation import gettext_lazy as _
3
 from django.utils.translation import gettext_lazy as _
39
 
37
 
40
 
38
 
41
 SEARCH_FACETS = {
39
 SEARCH_FACETS = {
42
-    'fields': OrderedDict([
43
-        ('product_class', {'name': _('Type'), 'field': 'product_class'}),
44
-        ('rating', {'name': _('Rating'), 'field': 'rating'}),
45
-        ('category', {'name': _('Category'), 'field': 'category'}),
46
-    ]),
47
-    'queries': OrderedDict([
48
-        ('price_range',
49
-         {
50
-             'name': _('Price range'),
51
-             'field': 'price',
52
-             'queries': [
53
-                 (_('0 to 20'), '[0 TO 20]'),
54
-                 (_('20 to 40'), '[20 TO 40]'),
55
-                 (_('40 to 60'), '[40 TO 60]'),
56
-                 (_('60+'), '[60 TO *]'),
57
-             ]
58
-         }),
59
-    ]),
40
+    'fields': {
41
+        'product_class': {'name': _('Type'), 'field': 'product_class'},
42
+        'rating': {'name': _('Rating'), 'field': 'rating'},
43
+        'category': {'name': _('Category'), 'field': 'category'},
44
+    },
45
+    'queries': {
46
+        'price_range': {
47
+            'name': _('Price range'),
48
+            'field': 'price',
49
+            'queries': [
50
+                (_('0 to 20'), '[0 TO 20]'),
51
+                (_('20 to 40'), '[20 TO 40]'),
52
+                (_('40 to 60'), '[40 TO 60]'),
53
+                (_('60+'), '[60 TO *]'),
54
+            ]
55
+        },
56
+    },
60
 }
57
 }
61
 
58
 
62
 
59
 

+ 5
- 6
tox.ini 查看文件

1
 [tox]
1
 [tox]
2
 envlist =
2
 envlist =
3
-    py{36,37,38,39}-django{22,31,32}
3
+    py{37,38,39}-django{31,32}
4
     lint
4
     lint
5
     sandbox
5
     sandbox
6
     docs
6
     docs
11
 extras = test
11
 extras = test
12
 pip_pre = true
12
 pip_pre = true
13
 deps =
13
 deps =
14
-    django22: django>=2.2,<2.3
15
     django31: django>=3.1,<3.2
14
     django31: django>=3.1,<3.2
16
     django32: django>=3.2,<3.3
15
     django32: django>=3.2,<3.3
17
 
16
 
18
 [testenv:lint]
17
 [testenv:lint]
19
-basepython = python3.7
18
+basepython = python3.8
20
 deps =
19
 deps =
21
     -r{toxinidir}/requirements.txt
20
     -r{toxinidir}/requirements.txt
22
 allowlist_externals = npm
21
 allowlist_externals = npm
29
 
28
 
30
 
29
 
31
 [testenv:sandbox]
30
 [testenv:sandbox]
32
-basepython = python3.7
31
+basepython = python3.8
33
 deps =
32
 deps =
34
     -r{toxinidir}/requirements.txt
33
     -r{toxinidir}/requirements.txt
35
-    django>=2.2,<2.3
34
+    django>=3.2,<3.3
36
 allowlist_externals = make
35
 allowlist_externals = make
37
 commands =
36
 commands =
38
     make build_sandbox
37
     make build_sandbox
39
 
38
 
40
 [testenv:docs]
39
 [testenv:docs]
41
-basepython = python3.7
40
+basepython = python3.8
42
 allowlist_externals = make
41
 allowlist_externals = make
43
 changedir = {toxinidir}/docs
42
 changedir = {toxinidir}/docs
44
 pip_pre = false
43
 pip_pre = false

正在加载...
取消
保存