@@ -98,3 +98,109 @@ class Device(models.Model):
9898
9999# # source code continues here without further DateTimeField examples
100100```
101+
102+
103+ ## Example 2 from AuditLog
104+ [ Auditlog] ( https://github.com/jjkester/django-auditlog )
105+ ([ project documentation] ( https://django-auditlog.readthedocs.io/en/latest/ ) )
106+ is a [ Django] ( /django.html ) app that logs changes to Python objects,
107+ similar to the Django admin's logs but with more details and
108+ output formats. Auditlog's source code is provided as open source under the
109+ [ MIT license] ( https://github.com/jjkester/django-auditlog/blob/master/LICENSE ) .
110+
111+ [ ** django-auditlog / src / auditlog / diff.py** ] ( https://github.com/jjkester/django-auditlog/blob/master/src/auditlog/diff.py )
112+
113+ ``` python
114+ from __future__ import unicode_literals
115+
116+ from django.conf import settings
117+ from django.core.exceptions import ObjectDoesNotExist
118+ ~~ from django.db.models import Model, NOT_PROVIDED , DateTimeField
119+ from django.utils import timezone
120+ from django.utils.encoding import smart_text
121+
122+
123+ def track_field (field ):
124+ """
125+ Returns whether the given field should be tracked by Auditlog.
126+ Untracked fields are many-to-many relations and relations to
127+ the Auditlog LogEntry model.
128+ :param field: The field to check.
129+ :type field: Field
130+ :return: Whether the given field should be tracked.
131+ :rtype: bool
132+ """
133+ from auditlog.models import LogEntry
134+ # Do not track many to many relations
135+ if field.many_to_many:
136+ return False
137+
138+ # Do not track relations to LogEntry
139+ if getattr (field, ' remote_field' , None ) is not None and \
140+ field.remote_field.model == LogEntry:
141+ return False
142+
143+ # 1.8 check
144+ elif getattr (field, ' rel' , None ) is not None and \
145+ field.rel.to == LogEntry:
146+ return False
147+
148+ return True
149+
150+
151+ def get_fields_in_model (instance ):
152+ """
153+ Returns the list of fields in the given model instance.
154+ Checks whether to use the official _meta API or use the raw
155+ data. This method excludes many to many fields.
156+ :param instance: The model instance to get the fields for
157+ :type instance: Model
158+ :return: The list of fields for the given model (instance)
159+ :rtype: list
160+ """
161+ assert isinstance (instance, Model)
162+
163+ # Check if the Django 1.8 _meta API is available
164+ use_api = hasattr (instance._meta, ' get_fields' ) and \
165+ callable (instance._meta.get_fields)
166+
167+ if use_api:
168+ return [f for f in instance._meta.get_fields() if track_field(f)]
169+ return instance._meta.fields
170+
171+
172+ def get_field_value (obj , field ):
173+ """
174+ Gets the value of a given model instance field.
175+ :param obj: The model instance.
176+ :type obj: Model
177+ :param field: The field you want to find the value of.
178+ :type field: Any
179+ :return: The value of the field as a string.
180+ :rtype: str
181+ """
182+ ~~ if isinstance (field, DateTimeField):
183+ ~~ # DateTimeFields are timezone-aware, so we need
184+ ~~ # to convert the field to its naive form before we
185+ ~~ # can accuratly compare them for changes.
186+ ~~ try :
187+ ~~ value = field.to_python(getattr (obj, field.name,
188+ ~~ None ))
189+ ~~ if value is not None and settings.USE_TZ and \
190+ ~~ not timezone.is_naive(value):
191+ ~~ value = timezone.make_naive(value,
192+ ~~ timezone = timezone.utc)
193+ ~~ except ObjectDoesNotExist:
194+ ~~ value = field.default if field.default \
195+ ~~ is not NOT_PROVIDED else None
196+ else :
197+ try :
198+ value = smart_text(getattr (obj, field.name, None ))
199+ except ObjectDoesNotExist:
200+ value = field.default if field.default \
201+ is not NOT_PROVIDED else None
202+
203+ return value
204+
205+ # # ... source file continues here without further DateTime examples ...
206+ ```
0 commit comments