Oscar 2.0 release notes

release

2019-07-04

Welcome to Oscar 2.0. This is a significant release which includes a number of new features and backwards incompatible changes. In particular the way Oscar configures apps has been refactored and projects that have forked apps will need to follow the section on Migrating forked apps.

Compatibility

Oscar 2.0 is compatible with Django 1.11, Django 2.1 and Django 2.2 as well as Python 3.5, 3.6 and 3.7.

Support for Python 2.7 and Python 3.4 has been dropped.

What’s new in Oscar 2.0?

  • Added an is_public field to the Product model that is used to exclude products from the browsable queryset. A browsable_dashboard queryset is provided for use in the dashboard, which includes non-public products. This is a model change, so you will need to run the supplied migrations.

  • Added an order.OrderStatusChange model that is used to log order status changes applied by Order.set_status(). This is a new model, so you will need to run the supplied migrations.

  • Added an OSCAR_OFFERS_INCL_TAX setting which can be used to configure whether offer discounts are applied on the tax-inclusive amount. This defaults to False, to preserve the original behaviour of discount application.

  • Added database index definitions for commonly queried fields in a range of models. See #2875. This will require projects that have forked Oscar apps to generate corresponding migrations.

  • Added a filter_by_attributes method on the ProductQuerySet, to allow database-level filtering of products by attribute.

  • Added support for re-ordering product images in the dashboard, and for adding an arbitrary number of additional images into the formset.

  • Added an OSCAR_THUMBNAILER setting can be used to customise thumbnail generation. Support is included for Sorl and Easy Thumbnails. The default is 'oscar.core.thumbnails.SorlThumbnail'.

  • Added oscar_thumbnail template tag (to image_tags) to generate thumbnails in templates. All uses of Sorl’s thumbnail template tag in the shipped templates have been replaced with oscar_thumbnail.

  • sorl-thumbnail has been dropped as a dependency. Use pip install django-oscar[sorl-thumbnail] or pip install django-oscar[easy-thumbnails] to explicitly install the dependencies for either of the two supported thumbnailers.

  • Added the ability to manage catalogue.Option objects from the dashboard.

Removal of deprecated features

  • Product alert emails are now sent as Communication Events and the deprecated product alert email templates have been removed. The templates for these emails have been replaced as follows:

    • customer/alerts/emails/confirmation_subject.txt to customer/emails/commtype_product_alert_confirmation_subject.txt

    • customer/alerts/emails/confirmation_body.txt to customer/emails/commtype_product_alert_confirmation_body.txt

    • customer/alerts/emails/alert_subject.txt to customer/emails/commtype_product_alert_subject.txt

    • customer/alerts/emails/alert_body.txt to customer/emails/commtype_product_alert_body.txt

  • Support for category URLs without a primary key has been removed.

    Enforcement of unique slugs for categories has also been removed, as enforcing this was inefficient and not thread safe. Since a primary key is now required for category URLs, there is no need for slugs to be unique.

  • customer.forms.SetPasswordForm and customer.forms.PasswordChangeForm have been removed. Use django.contrib.auth.forms.SetPasswordForm and django.contrib.auth.forms.PasswordChangeForm instead.

  • The views.decorators.staff_member_required decorator has been removed. Use permissions_required(['is_staff'] instead.

  • The UserAddress.num_orders property has been removed. Use num_orders_as_shipping_address and num_orders_as_billing_address instead.

  • Support has been removed for the dynamic loading of formset classes that were moved in previous releases. Projects must update their get_class calls to use the new paths. The paths that have changed are as follows:

    Old path

    New path

    Affected classes

    basket.forms

    basket.formsets

    BaseBasketLineFormSet

    BasketLineFormSet

    BaseSavedLineFormSet

    SavedLineFormSet

    dashboard.catalogue.forms

    dashboard.catalogue.formsets

    BaseStockRecordFormSet

    StockRecordFormSet

    BaseProductCategoryFormSet

    ProductCategoryFormSet

    BaseProductImageFormSet

    ProductImageFormSet

    BaseProductRecommendationFormSet

    ProductRecommendationFormSet

    ProductAttributesFormSet

    wishlists.forms

    wishlists.formsets

    LineFormset

Minor changes

  • Dropped action="" and action="." attributes, following the lead of Django and as per the HTML5 specification.

  • Replaced use of Django’s procedural authentication views with the corresponding class-based views.

  • OrderPlacementMixin.get_message_context() is now passed a code argument specifying the communication event type code for the message being sent.

  • We’ve dropped the dependency on Unidecode due to license incompatibilities, oscar.core.utils.default_slugifier now uses oscar.core.utils.cautious_slugify to handle Unicode characters in slugs when OSCAR_SLUG_ALLOW_UNICODE is False.

  • Fixed input validation for dashboard.offers.forms.BenefitForm when a range was specified but other fields were empty.

  • Fixed calculation of weight-based shipping charges in cases where the basket weight is an exact multiple of a weight band’s upper limit.

  • The sort_by field on catalogue.reviews.SortReviewsForm was made optional and the logic in ProductReviewList adjusted so that the form fields don’t have to be rendered manually because of form errors.

  • Added a datetime_filters tag library that provides a timedelta template filter for rendering time deltas in human readable format.

  • OSCAR_OFFER_ROUNDING_FUNCTION previously accepted a function as its value. It now only accepts a dotted path to a function as its value

  • Fixed the logic of offers.Range.all_products() to make it consistent with Range.contains_product() in excluding products specified in excluded_product_ids.

  • Added a COMPARISON_FIELDS constant to catalogue.Category to restrict which fields are fetched from the database when performing category comparison queries.

  • Significantly improved the database efficiency of the category_tree template tag.

  • Order confirmation emails now include an order status link for authenticated users, as well as guest users, and order status is displayed consistently in both logged-in and anonymous order detail views.

  • Fixed display of styled HTML emails in account email detail views, wrapping them in an iframe to avoid leakage of styles into the page.

  • Bootstrap datetime picker JS/CSS assets removed from base layout, see #2584.

  • Oscar’s 500 error template no longer inherits other templates and does not use any template template tags and styling to avoid potential errors caused by the template itself (see #2971).

  • Line discounts are now capped to a minimum of zero - i.e., negative discounts will not be reported.

Backwards incompatible changes in Oscar 2.0

  • Redirection to the parent detail view for child products is disabled by default. Child products now have their own detail view, which allows displaying their price and images independently from the parent product. To revert to the previous behaviour of redirecting to the parent product, set oscar.apps.catalogue.views.ProductDetailView.enforce_parent to False.

  • Renamed the modules containing the Django app config classes for Oscar apps (apart from the oscar app), from config to apps.

  • Removed the app modules of Oscar apps, moving the configuration (related to permissions, URLconfs, and feature hiding) they contained into the apps’ Django app config classes. They include the following attributes: name (since renamed namespace), login_url, hidable_feature_name, permissions_map, and default_permissions; methods: :meth:get_urls, :meth:post_process_urls, :meth:get_permissions, :meth:get_url_decorator, and :meth:urls; and their respective view classes. The composite config classes for normal Oscar apps are subclasses of oscar.core.application.OscarConfig (previously oscar.core.application.Application), and for Oscar Dashboard apps oscar.core.application.OscarDashboardConfig (previously oscar.core.application.DashboardApplication).

  • Removed the application variable, which previously held an Oscar app config instance, from the Oscar app config module. A single Django/Oscar app config instance is now registered in the Django app registry, for each app label. It should be obtained by looking it up in the Django app registry.

  • Changed the values returned by the Oscar app config urls property. It now returns a tuple containing the list of URL patterns, the app namespace (which could previously be None, but not any more), and the instance namespace (which would previously be overridden by the app namespace, if left blank, but must now be explicitly set). To include URLs with an instance namespace, use the form app_config.urls, and to include URLs without an instance namespace, use the form django.conf.urls.include(app_config.urls[0]).

  • Removed oscar.get_core_apps. Overriding apps is now done by replacing the Oscar app entry in the INSTALLED_APPS setting with that of the forked app.

  • Changed the calling signature for the oscar_fork_app management command. The app_label argument is the Django app label of the app to be forked. target_path is the directory into which the new app shall be copied. new_app_subpackage is the optional dotted path to the package of the new app, from which, together with the target_path, the full Python path to the app will be derived. If new_app_subpackage is omitted, then the package of the app being forked will be used instead.

  • Removed the promotions app. The app is now available in a separate package - django_oscar_promotions.

  • OSCAR_MAIN_TEMPLATE_DIR setting has been removed and existing templates updated with the full path. See #1378, #2250. Please update your templates accordingly.

  • OSCAR_SLUG_FUNCTION previously accepted a function as its value. It now only accepts a dotted path to a function as its value. Such functions must also now take a allow_unicode kwarg.

Migrating forked apps

In release 2.0 the way apps are configured has been substantially refactored to merge Oscar’s Application class with Django’s AppConfig class. For each app that you have forked, you will need to:

  • Rename the config.py module to apps.py.

  • Change the default_app_config variable in __.init__.py to point to apps instead of config.

  • Update your AppConfig subclass in the apps.py module to either inherit from the parent app’s AppConfig or use either oscar.core.application.OscarConfig or oscar.core.application.OscarDashboardConfig.

  • Move any changes you’ve made to the Oscar Application subclass in the app.py module, to the AppConfig subclass in the apps.py module.

  • Rename the name attribute to namespace.

  • In your project URLconf and in get_urls methods replace the application import by finding the app in the Django app registry.

from django.apps import apps
application = apps.get_app_config('your_app_name')
  • If the urls you’re including don’t define an instance namespace then use include(application.urls[0]), which only passes in the list of URL patterns.

    Note

    Because of the way dynamic class loading now works, when forking dashboard apps, the oscar.apps.dashboard app also needs to be forked; and the forked dashboard app’s code must live inside the forked oscar.apps.dashboard app’s directory.

    Similarly, when forking oscar.apps.catalogue.reviews, oscar.apps.catalogue needs to be forked as well; and the forked oscar.apps.catalogue.reviews app’s code must live inside the forked oscar.apps.catalogue app’s directory.

Dependency changes

  • Dropped mock as a dependency in favour of unittests.mock.

  • Upgraded bootstrap to version 3.4.1.

  • Upgraded jquery to 3.4.1.

  • Dropped jquery.inputmask in favour of inputmask and upgraded to 4.0.2.

  • Upgraded less to 3.8.1.

  • Upgraded tinymce to version 4.8.3.

Deprecated features

  • offer.Range.contains() is deprecated. Use contains_product() instead.

  • catalogue.managers.ProductManager is deprecated. Use catalogue.managers.ProductQuerySet.as_manager() instead.

  • catalogue.managers.BrowsableProductManager is deprecated. Use Product.objects.browsable() instead.

  • catalogue.Product.browseable is deprecated. Use Product.objects.browseable() instead.