Repository: netzkolchose/django-computedfields (language: python)

Issue:
release django 4.1 version



Discussion / hints:

Fix patch:
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index a160ef3..924b7b5 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -50,7 +50,7 @@ jobs:
         parallel: true
         flag-name: Unit Test
 
-  django_40:
+  django_41:
 
     runs-on: ubuntu-latest
     strategy:
@@ -67,7 +67,7 @@ jobs:
     - name: Install dependencies
       run: |
         python -m pip install --upgrade pip
-        pip install "Django~=4.0"
+        pip install "Django~=4.1"
         pip install -r example/requirements-ci.txt
     - name: Setup DB
       run: |
@@ -112,7 +112,7 @@ jobs:
     - name: Install dependencies
       run: |
         python -m pip install --upgrade pip
-        pip install "Django~=4.0"
+        pip install "Django~=4.1"
         pip install -r example/requirements-ci.txt
     - name: Setup DB
       run: |
@@ -160,7 +160,7 @@ jobs:
     - name: Install dependencies
       run: |
         python -m pip install --upgrade pip
-        pip install "Django~=4.0"
+        pip install "Django~=4.1"
         pip install -r example/requirements-ci.txt
     - name: Setup DB
       run: |
@@ -209,7 +209,7 @@ jobs:
     - name: Install dependencies
       run: |
         python -m pip install --upgrade pip
-        pip install "Django~=4.0"
+        pip install "Django~=4.1"
         pip install -r example/requirements-ci.txt
     - name: Setup DB
       run: |
@@ -261,7 +261,7 @@ jobs:
     - name: Install dependencies
       run: |
         python -m pip install --upgrade pip
-        pip install "Django~=4.0"
+        pip install "Django~=4.1"
         pip install -r example/requirements-ci.txt
     - name: Setup DB
       run: |
@@ -285,7 +285,7 @@ jobs:
 
 
   coveralls_finish:
-    needs: [django_32, django_40, mysql, postgres, mariadb, sqlite333]
+    needs: [django_32, django_41, mysql, postgres, mariadb, sqlite333]
     runs-on: ubuntu-latest
     steps:
     - name: Coveralls Finished
diff --git a/README.md b/README.md
index ddf8d02..62b71f7 100644
--- a/README.md
+++ b/README.md
@@ -81,6 +81,10 @@ The documentation can be found [here](https://django-computedfields.readthedocs.
 
 
 #### Changelog ####
+
+- 0.2.1
+    - Django 4.1 support
+
 - 0.2.0 - next beta release
     - new features:
         - better memory control for the update resolver via
diff --git a/computedfields/__init__.py b/computedfields/__init__.py
index 7fd229a..fc79d63 100644
--- a/computedfields/__init__.py
+++ b/computedfields/__init__.py
@@ -1,1 +1,1 @@
-__version__ = '0.2.0'
+__version__ = '0.2.1'
diff --git a/docs/manual.rst b/docs/manual.rst
index 1550c5c..e495be4 100644
--- a/docs/manual.rst
+++ b/docs/manual.rst
@@ -165,9 +165,9 @@ pulls data from.
             # normal invocation with correct data pull across correct relation
             return self.nullable_relation.field
 
-    A special case in this regard are m2m relations during the first save of a newly
-    created instance, which cannot access the relation yet. You have to handle this case
-    explicitly as well:
+    A special case in this regard are m2m relations (and also backrelations under Django >=4.1)
+    during the first save of a newly created instance, which cannot access the relation yet.
+    You have to handle this case explicitly:
 
     .. CODE:: python
 
@@ -582,6 +582,9 @@ a similar feature in Django's ORM.
 
 Changelog
 ---------
+
+- 0.2.1
+    - Django 4.1 support
 - 0.2.0 - next beta release
     - new features:
         - better memory control for the update resolver via
diff --git a/setup.py b/setup.py
index d0c2f45..9ceb557 100644
--- a/setup.py
+++ b/setup.py
@@ -16,7 +16,7 @@ def get_version(path):
     packages=find_packages(exclude=['example']),
     include_package_data=True,
     install_requires=[
-        'Django>=2.2,<4.1',
+        'Django>=2.2,<4.2',
         'typing_extensions>=4.0.1',
         'django-fast-update'
     ],
@@ -28,7 +28,7 @@ def get_version(path):
     author='netzkolchose',
     author_email='j.breitbart@netzkolchose.de',
     url='https://github.com/netzkolchose/django-computedfields',
-    download_url='https://github.com/netzkolchose/django-computedfields/archive/0.2.0.tar.gz',
+    download_url='https://github.com/netzkolchose/django-computedfields/archive/0.2.1.tar.gz',
     keywords=['django', 'method', 'decorator', 'autoupdate', 'persistent', 'field'],
     classifiers=[
         'Development Status :: 4 - Beta',
@@ -38,7 +38,7 @@ def get_version(path):
         'Topic :: Software Development :: Libraries',
         'Framework :: Django',
         'Framework :: Django :: 3.2',
-        'Framework :: Django :: 4.0',
+        'Framework :: Django :: 4.1',
         'License :: OSI Approved :: MIT License',
         'Programming Language :: Python :: 3',
         'Programming Language :: Python :: 3.7',


Test patch:
diff --git a/example/test_full/models.py b/example/test_full/models.py
index 17b7c52..cdc518f 100644
--- a/example/test_full/models.py
+++ b/example/test_full/models.py
@@ -75,6 +75,8 @@ class NoRelatedA(ComputedFieldsModel):
     ])
     def comp(self):
         res = [self.name]
+        if not self.pk:
+            return '#'.join(res)
         for b in self.norelatedb_set.all():
             res.append(b.name)
             for c in b.norelatedc_set.all():
@@ -163,11 +165,15 @@ def comp(self):
 class Parent(ComputedFieldsModel):
     @computed(models.IntegerField(default=0), depends=[('children', ['parent'])])
     def children_count(self):
+        if not self.pk:
+            return 0
         return self.children.all().count()
 
     @computed(models.IntegerField(default=0), depends=[('children.subchildren', ['subparent'])])
     def subchildren_count(self):
         count = 0
+        if not self.pk:
+            return count
         for child in self.children.all():
             count += child.subchildren.all().count()
         return count
@@ -176,6 +182,8 @@ def subchildren_count(self):
     def subchildren_count_proxy(self):
         from functools import reduce
         from operator import add
+        if not self.pk:
+            return 0
         return reduce(add, (el.subchildren_count for el in self.children.all()), 0)
 
 class Child(ComputedFieldsModel):
@@ -183,6 +191,8 @@ class Child(ComputedFieldsModel):
 
     @computed(models.IntegerField(default=0), depends=[('subchildren', ['subparent'])])
     def subchildren_count(self):
+        if not self.pk:
+            return 0
         return self.subchildren.all().count()
 
 class Subchild(models.Model):
@@ -192,6 +202,8 @@ class Subchild(models.Model):
 class XParent(ComputedFieldsModel):
     @computed(models.IntegerField(default=0), depends=[('children', ['value'])])
     def children_value(self):
+        if not self.pk:
+            return 0
         return self.children.all().aggregate(sum=models.Sum('value'))['sum'] or 0
 
 class XChild(models.Model):
@@ -204,6 +216,8 @@ class DepBaseA(ComputedFieldsModel):
     @computed(models.CharField(max_length=256), depends=[('sub1.sub2.subfinal', ['name'])])
     def final_proxy(self):
         s = ''
+        if not self.pk:
+            return s
         for s1 in self.sub1.all().order_by('pk'):
             for s2 in s1.sub2.all().order_by('pk'):
                 for sf in s2.subfinal.all().order_by('pk'):
@@ -214,6 +228,8 @@ class DepBaseB(ComputedFieldsModel):
     @computed(models.CharField(max_length=256), depends=[('sub1.sub2.subfinal', ['name'])])
     def final_proxy(self):
         s = ''
+        if not self.pk:
+            return s
         for s1 in self.sub1.all().order_by('pk'):
             for s2 in s1.sub2.all().order_by('pk'):
                 for sf in s2.subfinal.all().order_by('pk'):
@@ -256,11 +272,15 @@ class Concrete(Abstract):
 class ParentOfAbstract(ComputedFieldsModel):
     @computed(models.IntegerField(default=0), depends=[('children', ['parent'])])
     def children_count(self):
+        if not self.pk:
+            return 0
         return self.children.all().count()
 
     @computed(models.IntegerField(default=0), depends=[('children.subchildren', ['subparent'])])
     def subchildren_count(self):
         count = 0
+        if not self.pk:
+            return count
         for child in self.children.all():
             count += child.subchildren.all().count()
         return count
@@ -269,6 +289,8 @@ def subchildren_count(self):
     def subchildren_count_proxy(self):
         from functools import reduce
         from operator import add
+        if not self.pk:
+            return 0
         return reduce(add, (el.subchildren_count for el in self.children.all()), 0)
 
 
@@ -282,6 +304,8 @@ class Meta:
 class ConcreteChild(AbstractChild):
     @computed(models.IntegerField(default=0), depends=[('subchildren', ['subparent'])])
     def subchildren_count(self):
+        if not self.pk:
+            return 0
         return self.subchildren.all().count()
 
 
@@ -472,6 +496,8 @@ class ParentReverseNotO(ComputedFieldsModel):
     )
     def children_comp(self):
         s = []
+        if not self.pk:
+            return '$'.join(s)
         for child in self.children.all():
             substr = child.name
             ss = []
@@ -502,6 +528,8 @@ class ParentReverseO(ComputedFieldsModel):
     )
     def children_comp(self):
         s = []
+        if not self.pk:
+            return '$'.join(s)
         for child in self.children.all():
             substr = child.name
             ss = []
@@ -572,6 +600,8 @@ class Registration(ComputedFieldsModel):
     @computed(models.FloatField(default=0), depends=[('payment_set', ['amount'])])
     def total_amount(self):
         paid = 0
+        if not self.pk:
+            return paid
         for cur_payment in self.payment_set.all():
             paid += cur_payment.amount
         return paid
@@ -697,6 +727,8 @@ class FixtureParent(ComputedFieldsModel):
 
     @computed(models.IntegerField(default=0), depends=[('children', ['parent'])])
     def children_count(self):
+        if not self.pk:
+            return 0
         return self.children.count()
 
 class FixtureChild(ComputedFieldsModel):
diff --git a/example/test_full/tests/test02_fkback.py b/example/test_full/tests/test02_fkback.py
index 2bc13b3..c2eb1fa 100644
--- a/example/test_full/tests/test02_fkback.py
+++ b/example/test_full/tests/test02_fkback.py
@@ -14,9 +14,9 @@ def setUp(self):
                   'func': lambda self: self.name},
             # one fk back step deps to comp field
             'F': {'depends': [('self', ['name']), ('fg_f', ['comp'])],
-                  'func': lambda self: self.name + ''.join(self.fg_f.all().values_list('comp', flat=True).order_by('pk'))},
+                  'func': lambda self: self.name + (''.join(self.fg_f.all().values_list('comp', flat=True).order_by('pk')) if self.pk else '')},
             'E': {'depends': [('self', ['name']), ('ef_f', ['comp'])],
-                  'func': lambda self: self.name + ''.join(self.ef_f.all().values_list('comp', flat=True).order_by('pk'))},
+                  'func': lambda self: self.name + (''.join(self.ef_f.all().values_list('comp', flat=True).order_by('pk')) if self.pk else '')},
             # multi fk back steps deps to non comp field
             'C': {'depends': [('self', ['name']), ('cd_f.de_f', ['name'])],
                   'func': lambda self: self.name + ''.join(
diff --git a/example/test_full/tests/test03_fk_fkback_mixed.py b/example/test_full/tests/test03_fk_fkback_mixed.py
index 9d1bac3..4a63d14 100644
--- a/example/test_full/tests/test03_fk_fkback_mixed.py
+++ b/example/test_full/tests/test03_fk_fkback_mixed.py
@@ -14,9 +14,9 @@ def setUp(self):
                       MODELS['G'].objects.filter(f_ga=self.f_ba).values_list('name', flat=True).order_by('pk'))},
             # fk_back + fk
             'F': {'depends': [('self', ['name']), ('fg_f.f_ga', ['name'])],
-                  'func': lambda self: self.name + ''.join(MODELS['A'].objects.filter(
+                  'func': lambda self: self.name + (''.join(MODELS['A'].objects.filter(
                       pk__in=self.fg_f.all().values_list('f_ga', flat=True).order_by('pk').distinct()
-                  ).values_list('name', flat=True).order_by('pk'))},
+                  ).values_list('name', flat=True).order_by('pk')) if self.pk else '')},
         })
         self.a = self.models.A(name='a')
         self.a.save()
@@ -287,9 +287,9 @@ def setUp(self):
         self.setDeps({
             # fk_back + fk_back + fk_back + fk + fk + fk
             'D': {'depends': [('self', ['name']), ('de_f.ef_f.fg_f.f_ga.f_ac.f_cb', ['name'])],
-                  'func': lambda self: self.name + ''.join(filter(bool, MODELS['G'].objects.filter(
+                  'func': lambda self: self.name + (''.join(filter(bool, MODELS['G'].objects.filter(
                       f_gf__in=MODELS['F'].objects.filter(
-                          f_fe__in=self.de_f.all())).values_list('f_ga__f_ac__f_cb__name', flat=True)))}
+                          f_fe__in=self.de_f.all())).values_list('f_ga__f_ac__f_cb__name', flat=True))) if self.pk else '')}
         })
         self.a = self.models.A(name='a')
         self.a.save()
diff --git a/example/test_full/tests/test04_fk_fkback_multiple.py b/example/test_full/tests/test04_fk_fkback_multiple.py
index 6043f89..d8da91c 100644
--- a/example/test_full/tests/test04_fk_fkback_multiple.py
+++ b/example/test_full/tests/test04_fk_fkback_multiple.py
@@ -8,9 +8,9 @@ def setUp(self):
             'C': {'depends': [('self', ['name']), ('f_cb.f_ba.ag_f.gd_f', ['name']), ('cd_f.de_f', ['name'])],
                   'func': lambda self: self.name + ''.join(
                       MODELS['D'].objects.filter(f_dg__in=MODELS['G'].objects.filter(
-                          f_ga=self.f_cb.f_ba)).values_list('name', flat=True).order_by('pk')) + ''.join(
+                          f_ga=self.f_cb.f_ba)).values_list('name', flat=True).order_by('pk')) + (''.join(
                       MODELS['E'].objects.filter(f_ed__in=self.cd_f.all()).values_list('name', flat=True).order_by('pk')
-                  )},
+                  ) if self.pk else '')},
         })
         self.a = self.models.A(name='a')
         self.a.save()
@@ -96,10 +96,11 @@ def setUp(self):
         self.setDeps({
             # fk_back + fk_back + fk_back + fk + fk + fk
             'D': {'depends': [['self', ['name']], ['de_f.ef_f.fg_f.f_ga.f_ac.f_cb', ['name']], ['f_dc.f_cb', ['name']]],
-                  'func': lambda self: self.name + ''.join(filter(bool, MODELS['G'].objects.filter(
+                  'func': lambda self: self.name + (''.join(filter(bool, MODELS['G'].objects.filter(
                       f_gf__in=MODELS['F'].objects.filter(
                           f_fe__in=self.de_f.all())).values_list(
-                      'f_ga__f_ac__f_cb__name', flat=True))) + self.f_dc.f_cb.name}
+                      'f_ga__f_ac__f_cb__name', flat=True))) if self.pk else '') + self.f_dc.f_cb.name
+            }
         })
         self.a = self.models.A(name='a')
         self.a.save()