|
1 |
| -import django |
2 |
| -from django.db import models |
3 |
| -from django.core.exceptions import ObjectDoesNotExist |
| 1 | +""" |
| 2 | +This is just a pure wrapper / alias module around django_serializable_model to |
| 3 | +still be able to import it with the original, unintended name of serializable. |
| 4 | +See https://github.com/agilgur5/django-serializable-model/issues/2 |
4 | 5 |
|
| 6 | +In the first major/breaking release, v1.0.0, this file should be deleted and |
| 7 | +the module removed from `setup.py`. |
| 8 | +""" |
5 | 9 |
|
6 |
| -class _SerializableQuerySet(models.query.QuerySet): |
7 |
| - """Implements the serialize method on a QuerySet""" |
8 |
| - def serialize(self, *args): |
9 |
| - serialized = [] |
10 |
| - for elem in self: |
11 |
| - serialized.append(elem.serialize(*args)) |
12 |
| - return serialized |
13 |
| - |
14 |
| - |
15 |
| -class SerializableManager(models.Manager): |
16 |
| - """Implements table-level serialization via SerializableQuerySet""" |
17 |
| - # backward compatibility for Django < 1.10 |
18 |
| - if django.VERSION < (1, 10): |
19 |
| - # when queried from a related Model, use this Manager |
20 |
| - use_for_related_fields = True |
21 |
| - |
22 |
| - def get_queryset(self): |
23 |
| - return _SerializableQuerySet(self.model) |
24 |
| - |
25 |
| - # backward compatibility for Django < 1.6 |
26 |
| - if django.VERSION < (1, 6): |
27 |
| - get_query_set = get_queryset |
28 |
| - |
29 |
| - def get_queryset_compat(self): |
30 |
| - get_queryset = (self.get_query_set |
31 |
| - if hasattr(self, 'get_query_set') |
32 |
| - else self.get_queryset) |
33 |
| - return get_queryset() |
34 |
| - |
35 |
| - # implement serialize on the Manager itself (on .objects, before .all()) |
36 |
| - def serialize(self, *args): |
37 |
| - return self.get_queryset_compat().serialize(*args) |
38 |
| - |
39 |
| - |
40 |
| -class SerializableModel(models.Model): |
41 |
| - """ |
42 |
| - Abstract Model that implements recursive serializability of models to |
43 |
| - dictionaries, both at the row and table level, with some overriding allowed |
44 |
| - """ |
45 |
| - objects = SerializableManager() |
46 |
| - |
47 |
| - class Meta: |
48 |
| - abstract = True |
49 |
| - # when queried from a related Model, use this Manager |
50 |
| - base_manager_name = 'SerializableManager' |
51 |
| - |
52 |
| - def serialize(self, *args, **kwargs): |
53 |
| - """ |
54 |
| - Serializes the Model object with model_to_dict_custom and kwargs, and |
55 |
| - proceeds to recursively serialize related objects as requested in args |
56 |
| - """ |
57 |
| - serialized = model_to_dict_custom(self, **kwargs) |
58 |
| - args = list(args) # convert tuple to list |
59 |
| - |
60 |
| - # iterate and recurse through all arguments |
61 |
| - index = 0 |
62 |
| - length = len(args) |
63 |
| - while index < length: |
64 |
| - # split the current element |
65 |
| - field_with_joins = args[index] |
66 |
| - field, join = _split_joins(field_with_joins) |
67 |
| - all_joins = [join] if join else [] # empty string to empty array |
68 |
| - |
69 |
| - # delete it from the list |
70 |
| - del args[index] |
71 |
| - length -= 1 |
72 |
| - |
73 |
| - # get all joins for this field from the arguments |
74 |
| - arg_joins = [_split_joins(arg, only_join=True) |
75 |
| - for arg in args if arg.startswith(field)] |
76 |
| - all_joins += arg_joins # combine all joins on this field |
77 |
| - |
78 |
| - # recurse if related object actually exists |
79 |
| - try: |
80 |
| - serialized[field] = getattr(self, field).serialize(*all_joins) |
81 |
| - except (AttributeError, ObjectDoesNotExist): |
82 |
| - pass |
83 |
| - |
84 |
| - # shrink length and remove all args that were recursed over |
85 |
| - length -= len(arg_joins) |
86 |
| - args = [arg for arg in args if not arg.startswith(field)] |
87 |
| - |
88 |
| - return serialized |
89 |
| - |
90 |
| - |
91 |
| -def model_to_dict_custom(instance, fields=None, exclude=None, editable=True): |
92 |
| - """ |
93 |
| - Custom model_to_dict function that differs by including all uneditable |
94 |
| - fields and excluding all M2M fields by default |
95 |
| - Also sets all ForeignKey fields to name + _id, similar to .values() |
96 |
| - """ |
97 |
| - # avoid circular import |
98 |
| - from django.db.models.fields.related import ForeignKey |
99 |
| - opts = instance._meta |
100 |
| - data = {} |
101 |
| - for f in opts.fields: |
102 |
| - # skip uneditable fields if editable kwarg is False |
103 |
| - if not editable and not f.ediable: |
104 |
| - continue |
105 |
| - # whitelisted fields only if fields kwarg is passed |
106 |
| - if fields and f.name not in fields: |
107 |
| - continue |
108 |
| - # blacklist fields from exclude kwarg |
109 |
| - if exclude and f.name in exclude: |
110 |
| - continue |
111 |
| - else: |
112 |
| - if isinstance(f, ForeignKey): |
113 |
| - data[f.name + '_id'] = f.value_from_object(instance) |
114 |
| - else: |
115 |
| - data[f.name] = f.value_from_object(instance) |
116 |
| - return data |
117 |
| - |
118 |
| - |
119 |
| -def _split_joins(join_string, only_join=False): |
120 |
| - """ |
121 |
| - Split a string into the field and it's joins, separated by __ as per |
122 |
| - Django convention |
123 |
| - """ |
124 |
| - split = join_string.split('__') |
125 |
| - field = split.pop(0) # the first field |
126 |
| - join = '__'.join(split) # the rest of the fields |
127 |
| - |
128 |
| - # return single join or tuple based on kwarg |
129 |
| - if only_join: |
130 |
| - return join |
131 |
| - return field, join |
| 10 | +from django_serializable_model import * # noqa F403, F401 |
0 commit comments