diff --git a/README.md b/README.md index 7375d0967..a340a764b 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,21 @@ # django-SHOP +**Django-SHOP** aims to be a the easy, fun and fast e-commerce counterpart to +[django-CMS](https://www.django-cms.org/). + [![Build Status](https://travis-ci.org/awesto/django-shop.svg?branch=master)](https://travis-ci.org/awesto/django-shop?branch=master) [![PyPI version](https://img.shields.io/pypi/v/django-shop.svg)](https://pypi.python.org/pypi/django-shop) +[![Python versions](https://img.shields.io/pypi/pyversions/django-shop.svg)](https://pypi.python.org/pypi/django-shop) [![Join the chat at https://gitter.im/awesto/django-shop](https://badges.gitter.im/awesto/django-shop.svg)](https://gitter.im/awesto/django-shop?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Software license](https://img.shields.io/pypi/l/django-shop.svg)](https://pypi.python.org/pypi/django-shop) [![Twitter Follow](https://img.shields.io/twitter/follow/djangoSHOP.svg?style=social&label=djangoSHOP)](https://twitter.com/djangoSHOP) -**Django-SHOP** aims to be a the easy, fun and fast e-commerce counterpart to -[django-CMS](https://www.django-cms.org/). - Here you can find the [full documentation for django-SHOP](https://django-shop.readthedocs.io/en/latest/). ## Version 1.1 has been released! -See below on how to install it using the Cookiecutter template. +See below on how to install it using the Cookiecutter template. It now supports up to django-CMS 3.7 +and Django-2.2. ## Build the database model out of the product's properties – not vice versa diff --git a/docs/changelog.rst b/docs/changelog.rst index 24ee275b3..125806f30 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -4,9 +4,17 @@ Changelog for django-SHOP ========================= +1.1.1 +===== +* Fix: Rendering text for full text index raised an exception. +* Upgrade calls to djangorestframework API to support version 3.9 and later. +* Fix: Generating email during purchansing operation raised an exception. + + 1.1 === +* Add support for Django-2.2, 2.1. Drop support for Django<1.11. * Add wrapper around Django's messages framework so that messages can be displayed asynchronously using a new AngularJS directive ````. * Add endpoint ``fetch_messages`` to fetch JSON description for toast-messages. diff --git a/docs/requirements.txt b/docs/requirements.txt index 035ebcf70..5830f4ca8 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -3,14 +3,14 @@ atomicwrites==1.3.0 attrs==18.2.0 babel==2.6.0 bleach==3.1.0 -certifi==2018.11.29 +certifi==2019.11.28 chardet==3.0.4 coverage==4.5.2 docutils==0.14 filelock==3.0.10 idna==2.8 imagesize==1.1.0 -jinja2==2.10 +jinja2==2.10.3 markupsafe==1.1.0 more-itertools==6.0.0; python_version > '2.7' packaging==19.0 @@ -33,6 +33,6 @@ toml==0.10.0 tox==3.7.0 tqdm==4.31.1 twine==1.13.0 -urllib3==1.24.1 +urllib3==1.25.7 virtualenv==16.4.0 webencodings==0.5.1 diff --git a/setup.py b/setup.py index ddef88fa8..73a671bb6 100644 --- a/setup.py +++ b/setup.py @@ -42,17 +42,17 @@ zip_safe=False, install_requires=[ 'Django>=1.11,<3.0', - 'django-post_office>=3.2.0', - 'django-filer>=1.4', - 'django-ipware>=1.1.1', - 'django-fsm>=2.4.0', - 'django-fsm-admin>=1.2.4', - 'djangorestframework>3.8,<3.9', - 'django-angular>2.2', - 'Django-Select2<7', + 'django-post_office', + 'django-filer', + 'django-ipware', + 'django-fsm', + 'django-fsm-admin', + 'djangorestframework>=3.9,<4', + 'django-angular', + 'Django-Select2', 'django-rest-auth', - 'django-admin-sortable2>=0.7.4', - 'django-formtools>1.0', - 'djangocms-cascade>1.1', + 'django-admin-sortable2', + 'django-formtools', + 'djangocms-cascade', ], ) diff --git a/shop/__init__.py b/shop/__init__.py index 7bac9386b..0a6bbcbb4 100644 --- a/shop/__init__.py +++ b/shop/__init__.py @@ -17,6 +17,6 @@ 11. git commit -m 'Start with ' 12. git push """ -__version__ = '1.1.dev' +__version__ = '1.1.1' default_app_config = 'shop.apps.ShopConfig' diff --git a/shop/context_processors.py b/shop/context_processors.py index 9ffb96a72..ee301f943 100644 --- a/shop/context_processors.py +++ b/shop/context_processors.py @@ -15,7 +15,7 @@ def customer(request): customer = CustomerModel.objects.get(pk=request.session['emulate_user_id']) except CustomerModel.DoesNotExist: customer = VisitingCustomer() - except KeyError: + except (AttributeError, KeyError): pass return {'customer': customer} diff --git a/shop/rest/fields.py b/shop/rest/fields.py index 47bbd3202..26f2bf97d 100644 --- a/shop/rest/fields.py +++ b/shop/rest/fields.py @@ -20,6 +20,9 @@ class JSONSerializerField(serializers.Field): """ Serializer field which transparently bypasses its object instead of serializing/deserializing. """ + def __init__(self, encoder=None, **kwargs): + super(JSONSerializerField, self).__init__(**kwargs) + def to_representation(self, obj): return obj diff --git a/shop/search/views.py b/shop/search/views.py index 3330d8a64..1039920c4 100644 --- a/shop/search/views.py +++ b/shop/search/views.py @@ -80,6 +80,8 @@ class CMSPageCatalogWrapper(object): :param filter_class: A filter set which must inherit from :class:`django_filters.FilterSet`. + :param pagination_class: A pagination class inheriting from :class:`rest_framework.pagination.BasePagination`. + :param search_serializer_class: The serializer class used to process the queryset returned by Haystack, while performing an autocomplete lookup. @@ -96,6 +98,7 @@ class CMSPageCatalogWrapper(object): limit_choices_to = models.Q() search_serializer_class = None # must be overridden by CMSPageCatalogWrapper.as_view() model_serializer_class = app_settings.PRODUCT_SUMMARY_SERIALIZER # may be overridden by CMSPageCatalogWrapper.as_view() + pagination_class = ProductListPagination filter_class = None # may be overridden by CMSPageCatalogWrapper.as_view() filter_backends = [CMSPagesFilterBackend] + list(api_settings.DEFAULT_FILTER_BACKENDS) cms_pages_fields = ['cms_pages'] @@ -116,7 +119,8 @@ def as_view(cls, **initkwargs): bases = (AddFilterContextMixin, AddSearchContextMixin, CMSPageSearchMixin, SearchView) attrs = dict(renderer_classes=self.renderer_classes, product_model=self.product_model, - limit_choices_to=self.limit_choices_to, filter_class=self.filter_class) + limit_choices_to=self.limit_choices_to, filter_class=self.filter_class, + pagination_class=self.pagination_class) self.search_view = type(str('CatalogSearchView'), bases, attrs).as_view( serializer_class=self.search_serializer_class, ) diff --git a/shop/templates/shop/admin/edit_inline/stacked-order.html b/shop/templates/shop/admin/edit_inline/stacked-order.html index 8fd51d478..37a8d00b9 100644 --- a/shop/templates/shop/admin/edit_inline/stacked-order.html +++ b/shop/templates/shop/admin/edit_inline/stacked-order.html @@ -1,30 +1,25 @@ -{% load i18n admin_urls admin_static %} -
+{% load i18n admin_urls static %} +
+

{{ inline_admin_formset.opts.verbose_name_plural|capfirst }}

{{ inline_admin_formset.formset.management_form }} {{ inline_admin_formset.formset.non_form_errors }} -{% for inline_admin_form in inline_admin_formset %}
-

{{ inline_admin_formset.opts.verbose_name|capfirst }}: {% if inline_admin_form.original %}{{ inline_admin_form.original }}{% if inline_admin_form.model_admin.show_change_link and inline_admin_form.model_admin.has_registered_model %} {% trans "Change" %}{% endif %} +{% for inline_admin_form in inline_admin_formset %}
+

{{ inline_admin_formset.opts.verbose_name|capfirst }}: {% if inline_admin_form.original %}{{ inline_admin_form.original }}{% if inline_admin_form.model_admin.show_change_link and inline_admin_form.model_admin.has_registered_model %} {% if inline_admin_formset.has_change_permission %}{% trans "Change" %}{% else %}{% trans "View" %}{% endif %}{% endif %} {% else %}#{{ forloop.counter }}{% endif %} {% if inline_admin_form.show_url %}{% trans "View on site" %}{% endif %} - {% if inline_admin_formset.formset.can_delete and inline_admin_form.original %}{{ inline_admin_form.deletion_field.field }} {{ inline_admin_form.deletion_field.label_tag }}{% endif %} + {% if inline_admin_formset.formset.can_delete and inline_admin_formset.has_delete_permission and inline_admin_form.original %}{{ inline_admin_form.deletion_field.field }} {{ inline_admin_form.deletion_field.label_tag }}{% endif %}

{% if inline_admin_form.form.non_field_errors %}{{ inline_admin_form.form.non_field_errors }}{% endif %} {% for fieldset in inline_admin_form %} {% include "shop/admin/includes/fieldset.html" %} {% endfor %} {% if inline_admin_form.needs_explicit_pk_field %}{{ inline_admin_form.pk_field.field }}{% endif %} - {{ inline_admin_form.fk_field.field }} + {% if inline_admin_form.fk_field %}{{ inline_admin_form.fk_field.field }}{% endif %}
{% endfor %} +

- - diff --git a/shop/templates/shop/admin/includes/fieldset.html b/shop/templates/shop/admin/includes/fieldset.html index 836854cc6..941587200 100644 --- a/shop/templates/shop/admin/includes/fieldset.html +++ b/shop/templates/shop/admin/includes/fieldset.html @@ -7,30 +7,28 @@
{% if line.fields|length_is:'1' %}{{ line.errors }}{% endif %} {% for field in line %} - + {% if not line.fields|length_is:'1' and not field.is_readonly %}{{ field.errors }}{% endif %} {% if field.is_checkbox %} {{ field.field }}{{ field.label_tag }} {% elif field.field.name|truncatechars:18 == 'render_as_html_...' %} {{ field.label_tag }} - {% with field.contents as contents %} - {% if contents %} + {% with field.contents as contents %}{% if contents %}

 

{{ contents }} {% else %}

- {% endif %} - {% endwith %} + {% endif %}{% endwith %} {% else %} {{ field.label_tag }} {% if field.is_readonly %} -

{{ field.contents }}

+
{{ field.contents }}
{% else %} {{ field.field }} {% endif %} {% endif %} {% if field.field.help_text %} -

{{ field.field.help_text|safe }}

+
{{ field.field.help_text|safe }}
{% endif %}
{% endfor %} diff --git a/shop/templatetags/shop_search_tags.py b/shop/templatetags/shop_search_tags.py index 58f3d055a..53c975a8b 100644 --- a/shop/templatetags/shop_search_tags.py +++ b/shop/templatetags/shop_search_tags.py @@ -51,8 +51,9 @@ def _get_value(self, context, editable=True, **kwargs): def get_value(self, context, **kwargs): context.update(sekizai()) + context['product'] = context['object'] try: - language_code = context['object']._current_language + language_code = context['product']._current_language except (KeyError, AttributeError): language_code = None context['request'] = EmulateHttpRequest(language_code) diff --git a/shop/urls/rest_api.py b/shop/urls/rest_api.py index 7fac7bb24..d00c4cc5d 100644 --- a/shop/urls/rest_api.py +++ b/shop/urls/rest_api.py @@ -13,9 +13,9 @@ from shop.views.catalog import ProductSelectView router = routers.DefaultRouter() # TODO: try with trailing_slash=False -router.register(r'cart', CartViewSet, base_name='cart') -router.register(r'watch', WatchViewSet, base_name='watch') -router.register(r'checkout', CheckoutViewSet, base_name='checkout') +router.register(r'cart', CartViewSet, basename='cart') +router.register(r'watch', WatchViewSet, basename='watch') +router.register(r'checkout', CheckoutViewSet, basename='checkout') def fetch_messages(request): diff --git a/tests/requirements.txt b/tests/requirements.txt index 677afe403..aed89ebbb 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -34,7 +34,7 @@ djangocms-admin-style==1.3.0 djangocms-bootstrap==1.1.2 djangocms-cascade==1.1.9 djangocms-text-ckeditor==3.8.0 -djangorestframework==3.8.2 +djangorestframework==3.11.0 drf-haystack==1.8.4 easy-thumbnails==2.6 elasticsearch==1.7.0 @@ -53,7 +53,7 @@ oauthlib==3.0.1 packaging==19.2 pathlib2==2.3.5; python_version > '2.7' phonenumbers==8.10.7 -Pillow==5.4.1 +pillow==7.0.0 pluggy==0.13.1 py==1.8.0 pyparsing==2.4.6 @@ -73,6 +73,6 @@ text-unidecode==1.2 toml==0.10.0 tox==3.7.0 Unidecode==1.0.23 -urllib3==1.24.1 +urllib3==1.25.7 webencodings==0.5.1 zipp==0.6.0