Repository: django-oscar/django-oscar

Issue:
Some dashboard.promotions views are missing required fields attribute
For Django 1.8 compatibility many of the create and update views in `dashboard.promotions.views` require a fields attribute.

I can go through and make a list of all the views that need a filed attribute if required, or try and make a pull request.



Discussion:
We think this was fixed by https://github.com/django-oscar/django-oscar/pull/1682 What version of oscar are you using? Are you still experiencing problems?

#1682 added fields attributes to the forms, but the error I'm seeing is because of missing fields attributes on some of the dashboard.promotions.views

I'm testing the lastest Oscar master branch. I just did a git pull and migrate, still seeing the error. Below is a traceback.

I'm trying to update/edit an Image type of promotion.

If I add in a fields attribute to dashboard.promotions.views.UpdateImageView then this error does not occur. There a few views in the same file there which don't have a fields attribute and cause the same error.

```
    Environment:
    Request Method: GET
    Request URL: http://localhost:8000/dashboard/content-blocks/update/image/1/

    Django Version: 1.8.2
    Python Version: 2.7.9
    Installed Applications:
    ['grappelli',
     'django.contrib.auth',
     'django.contrib.contenttypes',
     'django.contrib.sessions',
     'django.contrib.sites',
     'django.contrib.messages',
     'django.contrib.staticfiles',
     'django.contrib.humanize',
     'django.contrib.admin',
     'django.contrib.admindocs',
     'django.contrib.flatpages',
     'clear_cache',
     'django_extensions',
     'django_rq',
     'floppyforms',
     'markup_deprecated',
     'robots',
     'compressor',
     'paypal',
     'widget_tweaks',
     'oscar',
     'oscar.apps.analytics',
     'oscar.apps.checkout',
     'oscar.apps.address',
     'oscar.apps.shipping',
     'apps.catalogue',
     'oscar.apps.catalogue.reviews',
     'oscar.apps.partner',
     'oscar.apps.basket',
     'oscar.apps.payment',
     'oscar.apps.offer',
     'oscar.apps.order',
     'oscar.apps.customer',
     'oscar.apps.promotions',
     'oscar.apps.search',
     'oscar.apps.voucher',
     'oscar.apps.wishlists',
     'oscar.apps.dashboard',
     'oscar.apps.dashboard.reports',
     'oscar.apps.dashboard.users',
     'oscar.apps.dashboard.orders',
     'oscar.apps.dashboard.promotions',
     'apps.dashboard.catalogue',
     'oscar.apps.dashboard.offers',
     'oscar.apps.dashboard.partners',
     'oscar.apps.dashboard.pages',
     'oscar.apps.dashboard.ranges',
     'oscar.apps.dashboard.reviews',
     'oscar.apps.dashboard.vouchers',
     'oscar.apps.dashboard.communications',
     'oscar.apps.dashboard.shipping',
     'haystack',
     'treebeard',
     'sorl.thumbnail',
     'django_tables2',
     'core',
     'apps.accounts',
     'apps.feature_content',
     'apps.films',
     'apps.testimonials',
     'extensions.django_rq',
     'extensions.rq_scheduler',
     'debug_toolbar',
     'sslserver']
    Installed Middleware:
    ('django.middleware.gzip.GZipMiddleware',
     'django.middleware.common.CommonMiddleware',
     'django.contrib.sessions.middleware.SessionMiddleware',
     'django.middleware.csrf.CsrfViewMiddleware',
     'django.contrib.auth.middleware.AuthenticationMiddleware',
     'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
     'django.contrib.messages.middleware.MessageMiddleware',
     'django.middleware.clickjacking.XFrameOptionsMiddleware',
     'oscar.apps.basket.middleware.BasketMiddleware',
     'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',
     'debug_toolbar.middleware.DebugToolbarMiddleware')


    Traceback:
    File "/Users/digicase/.virtualenvs/LETN-dev/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
      132.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)
    File "/Users/digicase/.virtualenvs/LETN-dev/lib/python2.7/site-packages/django/contrib/auth/decorators.py" in _wrapped_view
      22.                 return view_func(request, *args, **kwargs)
    File "/Users/digicase/.virtualenvs/LETN-dev/lib/python2.7/site-packages/django/views/generic/base.py" in view
      71.             return self.dispatch(request, *args, **kwargs)
    File "/Users/digicase/.virtualenvs/LETN-dev/lib/python2.7/site-packages/django/views/generic/base.py" in dispatch
      89.         return handler(request, *args, **kwargs)
    File "/Users/digicase/.virtualenvs/LETN-dev/lib/python2.7/site-packages/django/views/generic/edit.py" in get
      268.         return super(BaseUpdateView, self).get(request, *args, **kwargs)
    File "/Users/digicase/.virtualenvs/LETN-dev/lib/python2.7/site-packages/django/views/generic/edit.py" in get
      205.         form = self.get_form()
    File "/Users/digicase/.virtualenvs/LETN-dev/lib/python2.7/site-packages/django/views/generic/edit.py" in get_form
      73.             form_class = self.get_form_class()
    File "/Users/digicase/.virtualenvs/LETN-dev/lib/python2.7/site-packages/django/views/generic/edit.py" in get_form_class
      150.                     "the 'fields' attribute is prohibited." % self.__class__.__name__

    Exception Type: ImproperlyConfigured at /dashboard/content-blocks/update/image/1/
    Exception Value: Using ModelFormMixin (base class of UpdateImageView) without the 'fields' attribute is prohibited. 
```

Perhaps UpdateImageView requires a form class to be specified? At the moment only the model attribute is set:

```
class UpdateImageView(UpdateView):
    model = Image
```

https://github.com/django-oscar/django-oscar/blob/master/src/oscar/apps/dashboard/promotions/views.py#L280


Resolving patch:
diff --git a/src/oscar/apps/dashboard/promotions/views.py b/src/oscar/apps/dashboard/promotions/views.py
--- a/src/oscar/apps/dashboard/promotions/views.py
+++ b/src/oscar/apps/dashboard/promotions/views.py
@@ -174,6 +174,8 @@ class CreateMultiImageView(CreateView):
 
 class CreateAutomaticProductListView(CreateView):
     model = AutomaticProductList
+    fields = ['name', 'description', 'link_url', 'link_text', 'method',
+              'num_products']
 
 
 class CreateHandPickedProductListView(CreateView):
@@ -279,14 +281,18 @@ class UpdateSingleProductView(UpdateView):
 
 class UpdateImageView(UpdateView):
     model = Image
+    fields = ['name', 'link_url', 'image']
 
 
 class UpdateMultiImageView(UpdateView):
     model = MultiImage
+    fields = ['name', 'images']
 
 
 class UpdateAutomaticProductListView(UpdateView):
     model = AutomaticProductList
+    fields = ['name', 'description', 'link_url', 'link_text', 'method',
+              'num_products']
 
 
 class UpdateHandPickedProductListView(UpdateView):


Test patch: