File: index.rst

package info (click to toggle)
django-dirtyfields 1.3.1-4
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 272 kB
  • sloc: python: 812; makefile: 168
file content (219 lines) | stat: -rw-r--r-- 6,511 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219

Welcome to django-dirtyfields's documentation!
==============================================

Tracking dirty fields on a Django model instance.
Dirty means that field in-memory and database values are different.

`Source code <https://github.com/romgar/django-dirtyfields/>`_

Install
=======

::

    $ pip install django-dirtyfields


Usage
=====

To use ``django-dirtyfields``, you need to:

- Inherit from ``DirtyFieldsMixin`` in the Django model you want to track.

::

    from django.db import models
    from dirtyfields import DirtyFieldsMixin

    class TestModel(DirtyFieldsMixin, models.Model):
        """A simple test model to test dirty fields mixin with"""
        boolean = models.BooleanField(default=True)
        characters = models.CharField(blank=True, max_length=80)

- Use one of these 2 functions on a model instance to know if this instance is dirty, and get the dirty fields:

    * is\_dirty()
    * get\_dirty\_fields()


Examples
========

::

    >>> from tests.models import TestModel
    >>> tm = TestModel.objects.create(boolean=True,characters="testing")
    >>> tm.is_dirty()
    False
    >>> tm.get_dirty_fields()
    {}

    >>> tm.boolean = False

    >>> tm.is_dirty()
    True
    >>> tm.get_dirty_fields()
    {'boolean': True}


Checking foreign key fields.
----------------------------
By default, dirty functions are not checking foreign keys. If you want to also take these relationships into account, use ``check_relationship`` parameter:

::

    >>> from tests.models import TestModel
    >>> tm = TestModel.objects.create(fkey=obj1)
    >>> tm.is_dirty()
    False
    >>> tm.get_dirty_fields()
    {}

    >>> tm.fkey = obj2

    >>> tm.is_dirty()
    False
    >>> tm.is_dirty(check_relationship=True)
    True

    >>> tm.get_dirty_fields()
    {}
    >>> tm.get_dirty_fields(check_relationship=True)
    {'fkey': 1}


Checking many-to-many fields.
----------------------------
By default, dirty functions are not checking many-to-many fields. They are also a bit special, as a call to `.add()` method is directly
saving the related object to the database, thus the instance is never dirty.
If you want to check these relations, you should set ``ENABLE_M2M_CHECK`` to ``True`` in your model inheriting from
``DirtyFieldsMixin``, use ``check_m2m`` parameter and provide the values you want to test against:

::

    class TestM2MModel(DirtyFieldsMixin, models.Model):
        ENABLE_M2M_CHECK = True
        m2m_field = models.ManyToManyField(AnotherModel)

    >>> from tests.models import TestM2MModel
    >>> tm = TestM2MModel.objects.create()
    >>> tm2 = TestModel.objects.create()
    >>> tm.is_dirty()
    False
    >>> tm.m2m_field.add(tm2)
    >>> tm.is_dirty()
    False
    >>> tm.get_dirty_fields(check_m2m={'m2m_field': set([tm2.id])})
    {}
    >>> tm.get_dirty_fields(check_m2m={'m2m_field': set(["dummy_value])})
    {'m2m_field': set([tm2.id])}


This can be useful when validating forms with m2m relations, where you receive some ids and want to know if your object
in the database needs to be updated with these form values.

**WARNING**: this m2m mode will generate extra queries to get m2m relation values each time you will save your objects.
It can have serious performance issues depending on your project.


Checking a limited set of model fields.
-------------------------------------
If you want to check a limited set of model fields, you should set ``FIELDS_TO_CHECK`` in your model inheriting from ``DirtyFieldsMixin``:

::

    class TestModelWithSpecifiedFields(DirtyFieldsMixin, models.Model):
        boolean1 = models.BooleanField(default=True)
        boolean2 = models.BooleanField(default=True)
        FIELDS_TO_CHECK = ['boolean1']

    >>> from tests.models import TestModelWithSpecifiedFields
    >>> tm = TestModelWithSpecifiedFields.objects.create()

    >>> tm.boolean1 = False
    >>> tm.boolean2 = False

    >>> tm.get_dirty_fields()
    {'boolean1': True}


This can be used in order to increase performance.


Saving dirty fields.
----------------------------
If you want to only save dirty fields from an instance in the database (only these fields will be involved in SQL query), you can use ``save_dirty_fields`` method.

Warning: this ``save_dirty_fields`` method will trigger the same signals as django default ``save`` method.
But, in django 1.4.22-, as we are using under the hood an ``update`` method, we need to manually send these signals, so be aware that only ``sender`` and ``instance`` arguments are passed to the signal in that context.

::

    >>> tm.get_dirty_fields()
    {'fkey': 1}
    >>> tm.save_dirty_fields()
    >>> tm.get_dirty_fields()
    {}

Verbose mode
----------------------------
By default, when you use ``get_dirty_fields`` function, if there are dirty fields, only the old value is returned.
You can use ``verbose`` option to have more informations, for now a dict with old and new value:

::

    >>> tm.get_dirty_fields()
    {'fkey': 1}
    >>> tm.get_dirty_fields(verbose=True)
    {'fkey': {'saved': 1, 'current': 3}}


Custom comparison function
----------------------------
By default, ``dirtyfields`` compare the value between the database and the memory on a naive way (``==``).
After some issues (with timezones for example), a customisable comparison logic has been added.
You can now define how you want to compare 2 values by passing a function on DirtyFieldsMixin:

::

    from django.db import models
    from dirtyfields import DirtyFieldsMixin

    def your_function((new_value, old_value, param1):
        # Your custom comparison code here
        return new_value == old_value

    class TestModel(DirtyFieldsMixin, models.Model):
        compare_function = (your_function, {'param1': 5})


Have a look at ``dirtyfields.compare`` module to get some examples.

Why would you want this?
========================

When using :mod:`django:django.db.models.signals` (:data:`django.db.models.signals.pre_save` especially), it is useful to be able to see what fields have changed or not. A signal could change its behaviour depending on whether a specific field has changed, whereas otherwise, you only could work on the event that the model's :meth:`~django.db.models.Model.save` method had been called.


.. include:: contributing.rst
.. include:: credits.rst

Table of Contents:
==================

.. toctree::
   :maxdepth: 2

   contributing
   credits


Indices and tables
==================

* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`