Repository: saleor/saleor

Issue:
Django 2.1 compatibility
We should switch our supported Django version to the following list:
* Django 1.11 (current LTS)
* Django 2.1 (latest stable)

Current blockers:
* [x] `graphene-django` depends on an old version of `django-filters` (https://github.com/graphql-python/graphene-django/pull/492)
* [x] WeightInput passes floats to its base class which is a DecimalField
* [x] Some form widgets pass `renderer` to functions that don't expect it


Discussion:
A new version of `graphene_django`: `2.2.0` is now live on PyPI

Resolving patch:
diff --git a/saleor/core/weight.py b/saleor/core/weight.py
--- a/saleor/core/weight.py
+++ b/saleor/core/weight.py
@@ -70,8 +70,8 @@ def format_value(self, value):
             return value.value
         return value
 
-    def render(self, name, value, attrs=None):
-        widget = super().render(name, value, attrs=attrs)
+    def render(self, name, value, attrs=None, renderer=None):
+        widget = super().render(name, value, attrs=attrs, renderer=renderer)
         unit = get_default_weight_unit()
         translated_unit = dict(WeightUnits.CHOICES)[unit]
         return render_to_string(
@@ -79,7 +79,7 @@ def render(self, name, value, attrs=None):
             {'widget': widget, 'value': value, 'unit': translated_unit})
 
 
-class WeightField(forms.DecimalField):
+class WeightField(forms.FloatField):
     def __init__(self, *args, widget=WeightInput, min_value=0, **kwargs):
         if isinstance(widget, type):
             widget = widget(attrs={'type': 'number', 'step': 'any'})


Test patch:
diff --git a/tests/dashboard/test_product.py b/tests/dashboard/test_product.py
--- a/tests/dashboard/test_product.py
+++ b/tests/dashboard/test_product.py
@@ -975,9 +975,9 @@ def test_product_variant_form(product):
 
 
 def test_hide_field_in_variant_choice_field_form():
-    form = VariantChoiceField(Mock)
+    form = VariantChoiceField(Mock())
     variants, cart = MagicMock(), MagicMock()
-    variants.count.return_value = 1
+    variants.count.return_value = variants.all().count.return_value = 1
     variants.all()[0].pk = 'test'
 
     form.update_field_data(variants, discounts=None, taxes=None)
@@ -1092,10 +1092,13 @@ def test_product_form_seo_description_too_long(unavailable_product):
     assert form.is_valid()
 
     form.save()
-    assert len(unavailable_product.seo_description) <= 300
-    assert unavailable_product.seo_description == (
+    new_seo_description = unavailable_product.seo_description
+    assert len(new_seo_description) <= 300
+    assert new_seo_description.startswith(
         'Saying it fourth made saw light bring beginning kind over herb '
         'won\'t creepeth multiply dry rule divided fish herb cattle greater '
         'fly divided midst, gathering can\'t moveth seed greater subdue. '
         'Lesser meat living fowl called. Dry don\'t wherein. Doesn\'t above '
-        'form sixth. Image moving earth without f...')
+        'form sixth. Image moving earth without')
+    assert (
+        new_seo_description.endswith('...') or new_seo_description[-1] == '…')
diff --git a/tests/dashboard/test_staff.py b/tests/dashboard/test_staff.py
--- a/tests/dashboard/test_staff.py
+++ b/tests/dashboard/test_staff.py
@@ -125,7 +125,7 @@ def test_create_staff_and_set_password(admin_client):
     response = admin_client.post(url, data)
     assert response.status_code == 302
     new_user = User.objects.get(email='staff3@example.com')
-    assert not new_user.has_usable_password()
+    assert not new_user.password
     uid = urlsafe_base64_encode(force_bytes(new_user.pk)).decode()
     token = default_token_generator.make_token(new_user)
     response = admin_client.get(