Registry / database / django-dirtyfields

django-dirtyfields

JSON →
library1.9.9pypypi✓ verified 28d ago

django-dirtyfields is a small library for tracking 'dirty' fields on a Django model instance. A field is considered dirty if its in-memory value differs from the value currently saved in the database. The library is currently at version 1.9.9 and is actively maintained with regular updates to support new Django and Python versions.

pip install django-dirtyfields
INSTALL
IMPORT
SIG · DJANGO-DIRTYFIELDS
D
django-dirtyfields
databasepythonv1.9.9
Install
3.5s avg
Import
712ms
Disk
66MB
Pass rate
10/ 10
Env Coverage10 / 10
glibc
3.9–3.13
musl
3.9–3.13
Install & Compatibility
Where this runs
tested against v1.9.9 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
musl
py 3.10–3.95 runs
installs and imports cleanly · install 0.0s · import 0.746s · 66.3MB
glibc
py 3.10–3.95 runs
installs and imports cleanly · install 3.5s · import 0.678s · 67MB
66MB installed
● package 66MB
Code
Verified usage

Verified import paths — ran on the pinned version, not inferred.

DirtyFieldsMixin
✓ from dirtyfields import DirtyFieldsMixin

To use django-dirtyfields, inherit from `DirtyFieldsMixin` in your Django model. Then, use `is_dirty()` to check if any fields have changed, or `get_dirty_fields()` to retrieve a dictionary of the original values for modified fields.

from django.db import models from dirtyfields import DirtyFieldsMixin class ExampleModel(DirtyFieldsMixin, models.Model): characters = models.CharField(max_length=80, default='initial value') boolean = models.BooleanField(default=True) def __str__(self): return self.characters # Example Usage: # Assuming an active Django environment and database # model = ExampleModel.objects.create(characters='first value', boolean=True) # print(f'Is dirty initially? {model.is_dirty()}') # Expected: False # print(f'Dirty fields initially: {model.get_dirty_fields()}') # Expected: {} # model.characters = 'second value' # print(f'Is dirty after change? {model.is_dirty()}') # Expected: True # print(f'Dirty fields after change: {model.get_dirty_fields()}') # Expected: {'characters': 'first value'} # model.save() # print(f'Is dirty after save? {model.is_dirty()}') # Expected: False # model.boolean = False # print(f'Is dirty after another change? {model.is_dirty()}') # Expected: True
Debug
Known issues
breakingWith Django 6.0+, fields that are expressions (e.g., `F()` objects) are now refreshed or deferred after `Model.save()`. This means such a field may incorrectly appear as 'dirty' if subsequently changed in-memory, even if its actual database value didn't change based on your application logic, potentially leading to unexpected behavior in `is_dirty()` or `get_dirty_fields()`.
fix
Be aware of this behavior when using Django 6.0+ and expressions. Review `get_dirty_fields()` output for fields that might be affected by Django's internal refresh mechanism.
affects: Django 6.0+
gotchaThere's a limitation when using `django-dirtyfields` within database transactions. If a model instance is saved inside a `transaction.atomic()` block and the transaction is subsequently rolled back, the `is_dirty()` method might incorrectly return `False` (and `get_dirty_fields()` yield wrong results) because the instance's dirty state is reset after `save()` is called, irrespective of the transaction's eventual outcome.
fix
After a transaction rollback, call `model.refresh_from_db()` on the instance to restore its correct state from the database. Alternatively, manually restore the in-memory fields that were edited.
affects: All
gotchaUsing `DirtyFieldsMixin` introduces a small performance overhead as it needs to capture the model's state during initialization and saving to track changes. For models where dirty field tracking is not consistently needed, this overhead can be avoided by using a Proxy Model that inherits from `DirtyFieldsMixin` only when tracking is required.
fix
Consider defining your base model without `DirtyFieldsMixin` and create a proxy model that inherits from both your base model and `DirtyFieldsMixin` for scenarios where dirty field tracking is necessary.
affects: All
gotchaThe `save_dirty_fields()` method, while only persisting the changed fields, still internally calls the standard `save()` method on the model instance. This means that any `pre_save` or `post_save` signals registered for your model will still be triggered.
fix
Account for signal execution when using `save_dirty_fields()`. If your signals rely on specific fields being dirty, ensure they are written to handle this, or consider alternative approaches if fine-grained signal control is needed.
affects: All
Errors
Common errors & fixes
django-dirtyfields is_dirty returns False in transaction rollback
When a model instance is saved within a database transaction and the transaction is subsequently rolled back, `django-dirtyfields` incorrectly resets the model's dirty state after the `save()` call, leading to `is_dirty()` returning `False` even when the database value has reverted.
fix
After a transaction rollback, call `model.refresh_from_db()` on the model instance to synchronize its in-memory state with the database, or manually restore the edited fields.
AttributeError: 'NoneType' object has no attribute 'seek' django-dirtyfields
This error occurs when `django-dirtyfields` attempts to deepcopy a `File` or `ImageFieldFile` field (which might be `None`) within its internal `_as_dict` function, as `deepcopy` can fail on `NoneType` objects related to file handling.
fix
Create a custom mixin that overrides the `_as_dict` method in `DirtyFieldsMixin` to specifically handle `File` or `ImageFieldFile` instances by converting their values to strings (e.g., the filename) before deepcopying.
django-dirtyfields foreign key not tracking changes
`django-dirtyfields` does not check for changes in Foreign Key fields by default when determining if a model instance is dirty.
fix
To enable tracking for Foreign Key fields, pass the argument `check_relationship=True` to either the `is_dirty()` or `get_dirty_fields()` method.
Upgrade
Version history
1.9.9latest on PyPI · released Jan 22, 2026
Audit
Dependencies
DjangorequiredCore framework dependency for model integration. Requires Django >=3.2.
Agent activity
11 hits · last 30 days
node
10
Resources
django-dirtyfields — pip install django-dirtyfields · libregistry