Skip to content

Commit b7e9e70

Browse files
committed
(hotfix): resolve incorrect and inconsistent module naming
- see #2 - in Python-land, packages are _not_ imported by their package name, but their _module_ name - see also https://stackoverflow.com/a/54599368/3431180 - and the module name of this package was `serializable`, _not_ `django-serializable-model` - also in Python-land, one cannot use the standard `import` syntax for hyphenated modules, it will actually cause a SyntaxError - but for some reason it's not illegal to do so, and is allowed both in `setuptools` naming and PyPI naming (it is discouraged by PEP8) - rename serializable.py to django_serializable_model.py - leave serializable.py and just make it a wrapper / alias of django_serialiazable_model so as not to cause a breaking change (pkg): publish `django_serializable_model` module as well - don't remove `serializable` though so as to not cause a breaking change; should remove it in v1.0.0 (docs): use `django_serializable_model` in Usage docs
1 parent e82be57 commit b7e9e70

File tree

4 files changed

+149
-134
lines changed

4 files changed

+149
-134
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ Simplest use case, just implements the `.serialize()` function on a model:
4848

4949
```python
5050
from django.db import models
51-
from django-serializable-model import SerializableModel
51+
from django_serializable_model import SerializableModel
5252

5353

5454
class User(SerializableModel):
@@ -71,7 +71,7 @@ With an override of the default `.serialize()` function to only include whitelis
7171

7272
```python
7373
from django.db import models
74-
from django-serializable-model import SerializableModel
74+
from django_serializable_model import SerializableModel
7575

7676

7777
class User(SerializableModel):
@@ -104,7 +104,7 @@ With a simple, one-to-one relation:
104104

105105
```python
106106
from django.db import models
107-
from django-serializable-model import SerializableModel
107+
from django_serializable_model import SerializableModel
108108

109109

110110
class User(SerializableModel):
@@ -143,7 +143,7 @@ With a foreign key relation:
143143

144144
```python
145145
from django.db import models
146-
from django-serializable-model import SerializableModel
146+
from django_serializable_model import SerializableModel
147147

148148

149149
class User(SerializableModel):

django_serializable_model.py

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import django
2+
from django.db import models
3+
from django.core.exceptions import ObjectDoesNotExist
4+
5+
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

serializable.py

Lines changed: 8 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -1,131 +1,10 @@
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
45
6+
In the first major/breaking release, v1.0.0, this file should be deleted and
7+
the module removed from `setup.py`.
8+
"""
59

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

setup.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,12 @@
4848
],
4949
keywords=('django serializer serializers serializer-django serialize ' +
5050
'json dict queryset model modelmanager full wadofstuff'),
51-
py_modules=['serializable'],
51+
py_modules=[
52+
'django_serializable_model',
53+
# this is the original, unintended name, and should be removed in the
54+
# first breaking/major release, v1.0.0. See `serializable.py` comment.
55+
'serializable'
56+
],
5257
python_requires='>=2.7, <4',
5358
project_urls={ # Optional
5459
'Source': 'https://github.com/agilgur5/django-serializable-model/',

0 commit comments

Comments
 (0)