Skip to content

Commit 851ec57

Browse files
committed
add new timezone and datetime example
1 parent 9d9671c commit 851ec57

File tree

4 files changed

+214
-0
lines changed

4 files changed

+214
-0
lines changed

content/pages/examples/django/django-code-examples.markdown

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ output formats. Auditlog's source code is provided as open source under the
3636
Example code found in the AuditLog project:
3737

3838
* [django.contrib.admin.filters SimpleListFilter](/django-contrib-admin-filters-simplelistfilter-examples.html)
39+
* [django.db.models DateTimeField](/django-db-models-datetimefield-examples.html)
3940
* [django.utils.html format_html](/django-utils-html-format-html-examples.html)
4041

4142

content/pages/examples/django/django-db-models-datetimefield.markdown

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
```

content/pages/examples/django/django-utils-timezone.markdown

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,3 +271,108 @@ class EasyTimezoneMiddleware(middleware_base_class):
271271
~~ timezone.deactivate()
272272
```
273273

274+
275+
## Example 2 from AuditLog
276+
[Auditlog](https://github.com/jjkester/django-auditlog)
277+
([project documentation](https://django-auditlog.readthedocs.io/en/latest/))
278+
is a [Django](/django.html) app that logs changes to Python objects,
279+
similar to the Django admin's logs but with more details and
280+
output formats. Auditlog's source code is provided as open source under the
281+
[MIT license](https://github.com/jjkester/django-auditlog/blob/master/LICENSE).
282+
283+
[**django-auditlog / src / auditlog / diff.py**](https://github.com/jjkester/django-auditlog/blob/master/src/auditlog/diff.py)
284+
285+
```python
286+
from __future__ import unicode_literals
287+
288+
from django.conf import settings
289+
from django.core.exceptions import ObjectDoesNotExist
290+
from django.db.models import Model, NOT_PROVIDED, DateTimeField
291+
~~from django.utils import timezone
292+
from django.utils.encoding import smart_text
293+
294+
295+
def track_field(field):
296+
"""
297+
Returns whether the given field should be tracked by Auditlog.
298+
Untracked fields are many-to-many relations and relations to
299+
the Auditlog LogEntry model.
300+
:param field: The field to check.
301+
:type field: Field
302+
:return: Whether the given field should be tracked.
303+
:rtype: bool
304+
"""
305+
from auditlog.models import LogEntry
306+
# Do not track many to many relations
307+
if field.many_to_many:
308+
return False
309+
310+
# Do not track relations to LogEntry
311+
if getattr(field, 'remote_field', None) is not None and \
312+
field.remote_field.model == LogEntry:
313+
return False
314+
315+
# 1.8 check
316+
elif getattr(field, 'rel', None) is not None and \
317+
field.rel.to == LogEntry:
318+
return False
319+
320+
return True
321+
322+
323+
def get_fields_in_model(instance):
324+
"""
325+
Returns the list of fields in the given model instance.
326+
Checks whether to use the official _meta API or use the raw
327+
data. This method excludes many to many fields.
328+
:param instance: The model instance to get the fields for
329+
:type instance: Model
330+
:return: The list of fields for the given model (instance)
331+
:rtype: list
332+
"""
333+
assert isinstance(instance, Model)
334+
335+
# Check if the Django 1.8 _meta API is available
336+
use_api = hasattr(instance._meta, 'get_fields') and \
337+
callable(instance._meta.get_fields)
338+
339+
if use_api:
340+
return [f for f in instance._meta.get_fields() if track_field(f)]
341+
return instance._meta.fields
342+
343+
344+
def get_field_value(obj, field):
345+
"""
346+
Gets the value of a given model instance field.
347+
:param obj: The model instance.
348+
:type obj: Model
349+
:param field: The field you want to find the value of.
350+
:type field: Any
351+
:return: The value of the field as a string.
352+
:rtype: str
353+
"""
354+
if isinstance(field, DateTimeField):
355+
# DateTimeFields are timezone-aware, so we need
356+
# to convert the field to its naive form before we
357+
# can accuratly compare them for changes.
358+
~~ try:
359+
~~ value = field.to_python(getattr(obj, field.name,
360+
~~ None))
361+
~~ if value is not None and settings.USE_TZ and \
362+
~~ not timezone.is_naive(value):
363+
~~ value = timezone.make_naive(value,
364+
~~ timezone=timezone.utc)
365+
except ObjectDoesNotExist:
366+
value = field.default if field.default \
367+
is not NOT_PROVIDED else None
368+
else:
369+
try:
370+
value = smart_text(getattr(obj, field.name, None))
371+
except ObjectDoesNotExist:
372+
value = field.default if field.default \
373+
is not NOT_PROVIDED else None
374+
375+
return value
376+
377+
## ... source file continues here without further timezone examples ...
378+
```

content/pages/meta/00-change-log.markdown

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ on GitHub.
2323
* [django.http Http404](/django-http-http404-examples.html)
2424
* Updated code examples on the following pages:
2525
* [django.contrib admin](/django-contrib-admin-examples.html)
26+
* [django.db.models DateTimeField](/django-db-models-datetimefield-examples.html)
27+
* [django.utils timezone](/django-utils-timezone-examples.html)
2628

2729
### July
2830
* Pushed the [3000th commit](https://github.com/mattmakai/fullstackpython.com/commit/180051047a582b9154874b15dccb315600f23300)

0 commit comments

Comments
 (0)