mirror of
https://github.com/Hopiu/django-model-utils.git
synced 2026-03-16 20:00:23 +00:00
Merge branch 'master' into fix-prefetch-related
This commit is contained in:
commit
55cd816939
24 changed files with 142 additions and 156 deletions
|
|
@ -1,4 +1,4 @@
|
|||
# http://editorconfig.org
|
||||
# https://editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
|
|
|
|||
6
.github/workflows/release.yml
vendored
6
.github/workflows/release.yml
vendored
|
|
@ -11,14 +11,14 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.8
|
||||
python-version: 3.x
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
|
|
|
|||
13
.github/workflows/test.yml
vendored
13
.github/workflows/test.yml
vendored
|
|
@ -2,6 +2,9 @@ name: Test
|
|||
|
||||
on: [push, pull_request]
|
||||
|
||||
env:
|
||||
FORCE_COLOR: 1
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
|
@ -9,7 +12,7 @@ jobs:
|
|||
fail-fast: false
|
||||
max-parallel: 5
|
||||
matrix:
|
||||
python-version: ['3.7', '3.8', '3.9', '3.10']
|
||||
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12-dev']
|
||||
|
||||
services:
|
||||
postgres:
|
||||
|
|
@ -27,10 +30,10 @@ jobs:
|
|||
--health-retries 5
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v2
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
|
|
@ -40,7 +43,7 @@ jobs:
|
|||
echo "::set-output name=dir::$(pip cache dir)"
|
||||
|
||||
- name: Cache
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ steps.pip-cache.outputs.dir }}
|
||||
key:
|
||||
|
|
@ -64,6 +67,6 @@ jobs:
|
|||
DB_PORT: 5432
|
||||
|
||||
- name: Upload coverage
|
||||
uses: codecov/codecov-action@v1
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
name: Python ${{ matrix.python-version }}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
repos:
|
||||
- repo: https://github.com/PyCQA/isort
|
||||
rev: 5.11.1
|
||||
rev: 5.12.0
|
||||
hooks:
|
||||
- id: isort
|
||||
args: ['--profile', 'black', '--check-only', '--diff']
|
||||
|
|
@ -14,7 +14,7 @@ repos:
|
|||
files: ^(model_utils|tests)/
|
||||
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v3.3.1
|
||||
rev: v3.6.0
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: [--py37-plus]
|
||||
args: [--py38-plus]
|
||||
|
|
|
|||
18
.readthedocs.yml
Normal file
18
.readthedocs.yml
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# Read the Docs configuration file
|
||||
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
||||
# Project page: https://readthedocs.org/projects/django-model-utils/
|
||||
|
||||
version: 2
|
||||
|
||||
build:
|
||||
os: ubuntu-22.04
|
||||
tools:
|
||||
python: "3"
|
||||
|
||||
python:
|
||||
install:
|
||||
- method: pip
|
||||
path: .
|
||||
|
||||
sphinx:
|
||||
configuration: docs/conf.py
|
||||
15
CHANGES.rst
15
CHANGES.rst
|
|
@ -1,8 +1,17 @@
|
|||
Changelog
|
||||
=========
|
||||
|
||||
4.3.2
|
||||
-----
|
||||
To be released
|
||||
--------
|
||||
|
||||
- Remove ``SaveSignalHandlingModel``. This model used a modified copy of the internal Django method `Model.save_base()`
|
||||
and had not been updated for upstream bug fixes changes since its addition. (GH-#582)
|
||||
- Confirm support for `Django 4.2`
|
||||
- Add support for `Python 3.11` (GH-#545)
|
||||
- Add support for `Python 3.12` (GH-#545)
|
||||
- Drop support for `Python 3.7` (GH-#545)
|
||||
- Swedish translation (GH-#561)
|
||||
- Use proper column name instead of attname (GH-#573)
|
||||
- Fix `ValueError` when calling `prefetch_related` for tracked `ForeignKey` fields (Fixes GH-433)
|
||||
|
||||
4.3.1 (2022-11-15)
|
||||
|
|
@ -253,7 +262,7 @@ Changelog
|
|||
for the report. Thanks Matthew Schinckel for the fix. Merge of GH-130,
|
||||
fixes GH-83.
|
||||
|
||||
.. _IPython: http://ipython.org/
|
||||
.. _IPython: https://ipython.org/
|
||||
|
||||
|
||||
2.0.3 (2014.03.19)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ BUILDDIR = _build
|
|||
|
||||
# User-friendly check for sphinx-build
|
||||
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
|
||||
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
|
||||
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from https://sphinx-doc.org/)
|
||||
endif
|
||||
|
||||
# Internal variables.
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
# serve to show the default.
|
||||
|
||||
import os
|
||||
from pkg_resources import get_distribution
|
||||
import importlib.metadata
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
|
|
@ -49,7 +49,8 @@ parent_dir = os.path.dirname(os.path.dirname(__file__))
|
|||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
release = get_distribution('django-model-utils').version
|
||||
release = importlib.metadata.version('django-model-utils')
|
||||
|
||||
# for example take major/minor
|
||||
version = '.'.join(release.split('.')[:2])
|
||||
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ if errorlevel 9009 (
|
|||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
echo.https://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ If you don't explicitly call ``select_subclasses()`` or ``get_subclass()``,
|
|||
an ``InheritanceManager`` behaves identically to a normal ``Manager``; so
|
||||
it's safe to use as your default manager for the model.
|
||||
|
||||
.. _contributed by Jeff Elmore: http://jeffelmore.org/2010/11/11/automatic-downcasting-of-inherited-models-in-django/
|
||||
.. _contributed by Jeff Elmore: https://jeffelmore.org/2010/11/11/automatic-downcasting-of-inherited-models-in-django/
|
||||
|
||||
JoinManager
|
||||
-----------
|
||||
|
|
|
|||
|
|
@ -112,21 +112,3 @@ Also you can override the default uuid version. Versions 1,3,4 and 5 are now sup
|
|||
|
||||
|
||||
.. _`UUIDField`: https://github.com/jazzband/django-model-utils/blob/master/docs/fields.rst#uuidfield
|
||||
|
||||
|
||||
SaveSignalHandlingModel
|
||||
-----------------------
|
||||
|
||||
An abstract base class model to pass a parameter ``signals_to_disable``
|
||||
to ``save`` method in order to disable signals
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from model_utils.models import SaveSignalHandlingModel
|
||||
|
||||
class SaveSignalTestModel(SaveSignalHandlingModel):
|
||||
name = models.CharField(max_length=20)
|
||||
|
||||
obj = SaveSignalTestModel(name='Test')
|
||||
# Note: If you use `Model.objects.create`, the signals can't be disabled
|
||||
obj.save(signals_to_disable=['pre_save'] # disable `pre_save` signal
|
||||
|
|
|
|||
|
|
@ -20,4 +20,4 @@ Dependencies
|
|||
``django-model-utils`` supports `Django`_ 3.2+ (latest bugfix
|
||||
release in each series only) on Python 3.7+.
|
||||
|
||||
.. _Django: http://www.djangoproject.com/
|
||||
.. _Django: https://www.djangoproject.com/
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
from pkg_resources import DistributionNotFound, get_distribution
|
||||
import importlib.metadata
|
||||
|
||||
from .choices import Choices # noqa:F401
|
||||
from .tracker import FieldTracker, ModelTracker # noqa:F401
|
||||
|
||||
try:
|
||||
__version__ = get_distribution("django-model-utils").version
|
||||
except DistributionNotFound: # pragma: no cover
|
||||
__version__ = importlib.metadata.version('django-model-utils')
|
||||
except importlib.metadata.PackageNotFoundError: # pragma: no cover
|
||||
# package is not installed
|
||||
__version__ = None
|
||||
|
|
|
|||
BIN
model_utils/locale/sv/LC_MESSAGES/django.mo
Normal file
BIN
model_utils/locale/sv/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
53
model_utils/locale/sv/LC_MESSAGES/django.po
Normal file
53
model_utils/locale/sv/LC_MESSAGES/django.po
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
# This file is distributed under the same license as the django-model-utils package.
|
||||
#
|
||||
# Translators:
|
||||
# Tomas Walch <tomas@alternaliv.se>, 2022.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-11-23 14:46+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
#: model_utils/models.py:25
|
||||
msgid "created"
|
||||
msgstr "skapad"
|
||||
|
||||
#: model_utils/models.py:26
|
||||
msgid "modified"
|
||||
msgstr "ändrad"
|
||||
|
||||
#: model_utils/models.py:50
|
||||
msgid "start"
|
||||
msgstr "start"
|
||||
|
||||
#: model_utils/models.py:51
|
||||
msgid "end"
|
||||
msgstr "slut"
|
||||
|
||||
#: model_utils/models.py:66
|
||||
msgid "status"
|
||||
msgstr "status"
|
||||
|
||||
#: model_utils/models.py:67
|
||||
msgid "status changed"
|
||||
msgstr "status ändrad"
|
||||
|
||||
#: tests/models.py:106 tests/models.py:115 tests/models.py:124
|
||||
msgid "active"
|
||||
msgstr "aktiv"
|
||||
|
||||
#: tests/models.py:107 tests/models.py:116 tests/models.py:125
|
||||
msgid "deleted"
|
||||
msgstr "borttagen"
|
||||
|
||||
#: tests/models.py:108 tests/models.py:117 tests/models.py:126
|
||||
msgid "on hold"
|
||||
msgstr "väntande"
|
||||
|
||||
|
|
@ -194,7 +194,7 @@ class InheritanceQuerySet(InheritanceQuerySetMixin, QuerySet):
|
|||
where_queries.append('(' + ' AND '.join([
|
||||
'"{}"."{}" IS NOT NULL'.format(
|
||||
model._meta.db_table,
|
||||
field.attname, # Should this be something else?
|
||||
field.column,
|
||||
) for field in model._meta.parents.values()
|
||||
]) + ')')
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.db import models, router, transaction
|
||||
from django.db import models
|
||||
from django.db.models.functions import Now
|
||||
from django.db.models.signals import post_save, pre_save
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from model_utils.fields import (
|
||||
|
|
@ -172,60 +171,3 @@ class UUIDModel(models.Model):
|
|||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
|
||||
class SaveSignalHandlingModel(models.Model):
|
||||
"""
|
||||
An abstract base class model to pass a parameter ``signals_to_disable``
|
||||
to ``save`` method in order to disable signals
|
||||
"""
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
def save(self, signals_to_disable=None, *args, **kwargs):
|
||||
"""
|
||||
Add an extra parameters to hold which signals to disable
|
||||
If empty, nothing will change
|
||||
"""
|
||||
|
||||
self.signals_to_disable = signals_to_disable or []
|
||||
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def save_base(self, raw=False, force_insert=False,
|
||||
force_update=False, using=None, update_fields=None):
|
||||
"""
|
||||
Copied from base class for a minor change.
|
||||
This is an ugly overwriting but since Django's ``save_base`` method
|
||||
does not differ between versions 1.8 and 1.10,
|
||||
that way of implementing wouldn't harm the flow
|
||||
"""
|
||||
using = using or router.db_for_write(self.__class__, instance=self)
|
||||
assert not (force_insert and (force_update or update_fields))
|
||||
assert update_fields is None or len(update_fields) > 0
|
||||
cls = origin = self.__class__
|
||||
|
||||
if cls._meta.proxy:
|
||||
cls = cls._meta.concrete_model
|
||||
meta = cls._meta
|
||||
if not meta.auto_created and 'pre_save' not in self.signals_to_disable:
|
||||
pre_save.send(
|
||||
sender=origin, instance=self, raw=raw, using=using,
|
||||
update_fields=update_fields,
|
||||
)
|
||||
with transaction.atomic(using=using, savepoint=False):
|
||||
if not raw:
|
||||
self._save_parents(cls, using, update_fields)
|
||||
updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
|
||||
|
||||
self._state.db = using
|
||||
self._state.adding = False
|
||||
|
||||
if not meta.auto_created and 'post_save' not in self.signals_to_disable:
|
||||
post_save.send(
|
||||
sender=origin, instance=self, created=(not updated),
|
||||
update_fields=update_fields, raw=raw, using=using,
|
||||
)
|
||||
|
||||
# Empty the signals in case it might be used somewhere else in future
|
||||
self.signals_to_disable = []
|
||||
|
|
|
|||
0
model_utils/py.typed
Normal file
0
model_utils/py.typed
Normal file
|
|
@ -1,4 +1,4 @@
|
|||
pytest==6.2.5
|
||||
pytest-django==3.10.0
|
||||
psycopg2-binary==2.8.6
|
||||
psycopg2-binary==2.9.5
|
||||
pytest-cov==2.10.1
|
||||
|
|
|
|||
10
setup.py
10
setup.py
|
|
@ -29,7 +29,7 @@ setup(
|
|||
maintainer='JazzBand',
|
||||
url='https://github.com/jazzband/django-model-utils',
|
||||
packages=find_packages(exclude=['tests*']),
|
||||
python_requires=">=3.7",
|
||||
python_requires=">=3.8",
|
||||
install_requires=['Django>=3.2'],
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
|
|
@ -39,19 +39,23 @@ setup(
|
|||
'Operating System :: OS Independent',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Programming Language :: Python :: 3.9',
|
||||
'Programming Language :: Python :: 3.10',
|
||||
'Programming Language :: Python :: 3.11',
|
||||
'Programming Language :: Python :: 3.12',
|
||||
'Framework :: Django',
|
||||
'Framework :: Django :: 3.2',
|
||||
'Framework :: Django :: 4.0',
|
||||
'Framework :: Django :: 4.1',
|
||||
'Framework :: Django :: 4.2',
|
||||
],
|
||||
zip_safe=False,
|
||||
package_data={
|
||||
'model_utils': [
|
||||
'locale/*/LC_MESSAGES/django.po', 'locale/*/LC_MESSAGES/django.mo'
|
||||
'locale/*/LC_MESSAGES/django.po',
|
||||
'locale/*/LC_MESSAGES/django.mo',
|
||||
'py.typed',
|
||||
],
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ from model_utils import Choices
|
|||
from model_utils.fields import MonitorField, SplitField, StatusField, UUIDField
|
||||
from model_utils.managers import InheritanceManager, JoinManagerMixin, QueryManager
|
||||
from model_utils.models import (
|
||||
SaveSignalHandlingModel,
|
||||
SoftDeletableModel,
|
||||
StatusModel,
|
||||
TimeFramedModel,
|
||||
|
|
@ -67,6 +66,12 @@ class InheritanceManagerTestChild3(InheritanceManagerTestParent):
|
|||
parent_link=True, on_delete=models.CASCADE)
|
||||
|
||||
|
||||
class InheritanceManagerTestChild3_1(InheritanceManagerTestParent):
|
||||
parent_ptr = models.OneToOneField(
|
||||
InheritanceManagerTestParent, db_column="custom_parent_ptr",
|
||||
parent_link=True, on_delete=models.CASCADE)
|
||||
|
||||
|
||||
class InheritanceManagerTestChild4(InheritanceManagerTestParent):
|
||||
other_onetoone = models.OneToOneField(
|
||||
InheritanceManagerTestParent, related_name='non_inheritance_relation',
|
||||
|
|
@ -440,10 +445,6 @@ class CustomNotPrimaryUUIDModel(models.Model):
|
|||
uuid = UUIDField(primary_key=False)
|
||||
|
||||
|
||||
class SaveSignalHandlingTestModel(SaveSignalHandlingModel):
|
||||
name = models.CharField(max_length=20)
|
||||
|
||||
|
||||
class TimeStampWithStatusModel(TimeStampedModel, StatusModel):
|
||||
STATUS = Choices(
|
||||
("active", _("active")),
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ from tests.models import (
|
|||
InheritanceManagerTestChild1,
|
||||
InheritanceManagerTestChild2,
|
||||
InheritanceManagerTestChild3,
|
||||
InheritanceManagerTestChild3_1,
|
||||
InheritanceManagerTestChild4,
|
||||
InheritanceManagerTestGrandChild1,
|
||||
InheritanceManagerTestGrandChild1_2,
|
||||
|
|
@ -141,6 +142,7 @@ class InheritanceManagerTests(TestCase):
|
|||
'inheritancemanagertestchild1',
|
||||
'inheritancemanagertestchild2',
|
||||
'manual_onetoone', # this was set via parent_link & related_name
|
||||
'inheritancemanagertestchild3_1',
|
||||
'child4_onetoone',
|
||||
]
|
||||
self.assertEqual(set(results.subclasses),
|
||||
|
|
@ -256,7 +258,9 @@ class InheritanceManagerUsingModelsTests(TestCase):
|
|||
objs = InheritanceManagerTestParent.objects.select_subclasses().order_by('pk')
|
||||
objsmodels = InheritanceManagerTestParent.objects.select_subclasses(
|
||||
InheritanceManagerTestChild1, InheritanceManagerTestChild2,
|
||||
InheritanceManagerTestChild3, InheritanceManagerTestChild4,
|
||||
InheritanceManagerTestChild3,
|
||||
InheritanceManagerTestChild3_1,
|
||||
InheritanceManagerTestChild4,
|
||||
InheritanceManagerTestGrandChild1,
|
||||
InheritanceManagerTestGrandChild1_2).order_by('pk')
|
||||
self.assertEqual(set(objs.subclasses), set(objsmodels.subclasses))
|
||||
|
|
@ -278,6 +282,7 @@ class InheritanceManagerUsingModelsTests(TestCase):
|
|||
models = (InheritanceManagerTestChild1,
|
||||
InheritanceManagerTestChild2,
|
||||
InheritanceManagerTestChild3,
|
||||
InheritanceManagerTestChild3_1,
|
||||
InheritanceManagerTestChild4,
|
||||
InheritanceManagerTestGrandChild1,
|
||||
InheritanceManagerTestGrandChild1_2)
|
||||
|
|
@ -426,6 +431,12 @@ class InheritanceManagerUsingModelsTests(TestCase):
|
|||
|
||||
self.assertEqual([child3], list(results))
|
||||
|
||||
def test_limit_to_specific_subclass_with_custom_db_column(self):
|
||||
item = InheritanceManagerTestChild3_1.objects.create()
|
||||
results = InheritanceManagerTestParent.objects.instance_of(InheritanceManagerTestChild3_1)
|
||||
|
||||
self.assertEqual([item], list(results))
|
||||
|
||||
def test_limit_to_specific_grandchild_class(self):
|
||||
grandchild1 = InheritanceManagerTestGrandChild1.objects.get()
|
||||
results = InheritanceManagerTestParent.objects.instance_of(InheritanceManagerTestGrandChild1)
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
from django.db.models.signals import post_save, pre_save
|
||||
from django.test import TestCase
|
||||
|
||||
from tests.models import SaveSignalHandlingTestModel
|
||||
from tests.signals import post_save_test, pre_save_test
|
||||
|
||||
|
||||
class SaveSignalHandlingModelTests(TestCase):
|
||||
|
||||
def test_pre_save(self):
|
||||
pre_save.connect(pre_save_test, sender=SaveSignalHandlingTestModel)
|
||||
|
||||
obj = SaveSignalHandlingTestModel.objects.create(name='Test')
|
||||
delattr(obj, 'pre_save_runned')
|
||||
obj.name = 'Test A'
|
||||
obj.save()
|
||||
self.assertEqual(obj.name, 'Test A')
|
||||
self.assertTrue(hasattr(obj, 'pre_save_runned'))
|
||||
|
||||
obj = SaveSignalHandlingTestModel.objects.create(name='Test')
|
||||
delattr(obj, 'pre_save_runned')
|
||||
obj.name = 'Test B'
|
||||
obj.save(signals_to_disable=['pre_save'])
|
||||
self.assertEqual(obj.name, 'Test B')
|
||||
self.assertFalse(hasattr(obj, 'pre_save_runned'))
|
||||
|
||||
def test_post_save(self):
|
||||
post_save.connect(post_save_test, sender=SaveSignalHandlingTestModel)
|
||||
|
||||
obj = SaveSignalHandlingTestModel.objects.create(name='Test')
|
||||
delattr(obj, 'post_save_runned')
|
||||
obj.name = 'Test A'
|
||||
obj.save()
|
||||
self.assertEqual(obj.name, 'Test A')
|
||||
self.assertTrue(hasattr(obj, 'post_save_runned'))
|
||||
|
||||
obj = SaveSignalHandlingTestModel.objects.create(name='Test')
|
||||
delattr(obj, 'post_save_runned')
|
||||
obj.name = 'Test B'
|
||||
obj.save(signals_to_disable=['post_save'])
|
||||
self.assertEqual(obj.name, 'Test B')
|
||||
self.assertFalse(hasattr(obj, 'post_save_runned'))
|
||||
8
tox.ini
8
tox.ini
|
|
@ -1,7 +1,7 @@
|
|||
[tox]
|
||||
envlist =
|
||||
py{37,38,39,310}-dj32
|
||||
py{38,39,310}-dj{40,41,main}
|
||||
py{38,39,310,311,312}-dj{40,41,42,main}
|
||||
flake8
|
||||
isort
|
||||
|
||||
|
|
@ -11,6 +11,8 @@ python =
|
|||
3.8: py38, flake8, isort
|
||||
3.9: py39
|
||||
3.10: py310
|
||||
3.11: py311
|
||||
3.12: py312
|
||||
|
||||
[testenv]
|
||||
deps =
|
||||
|
|
@ -19,6 +21,7 @@ deps =
|
|||
dj32: Django==3.2.*
|
||||
dj40: Django==4.0.*
|
||||
dj41: Django==4.1.*
|
||||
dj42: Django==4.2.*
|
||||
djmain: https://github.com/django/django/archive/main.tar.gz
|
||||
ignore_outcome =
|
||||
djmain: True
|
||||
|
|
@ -26,11 +29,12 @@ ignore_errors =
|
|||
djmain: True
|
||||
passenv =
|
||||
CI
|
||||
FORCE_COLOR
|
||||
GITHUB_*
|
||||
DB_*
|
||||
usedevelop = True
|
||||
commands =
|
||||
pytest {posargs}
|
||||
python -m pytest {posargs}
|
||||
|
||||
[testenv:flake8]
|
||||
basepython =
|
||||
|
|
|
|||
Loading…
Reference in a new issue