Created
January 13, 2014 11:51
-
-
Save andir/8399017 to your computer and use it in GitHub Desktop.
flask-restless to_dict sqlalchemy homebrew method
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[6.848185062408447, 6.854957103729248, 6.840436935424805] | |
Timer unit: 1e-06 s | |
File: [..]/flask_restless/helpers.py | |
Function: to_dict at line 237 | |
Total time: 11.6519 s | |
Line # Hits Time Per Hit % Time Line Contents | |
============================================================== | |
237 def to_dict(instance, deep=None, exclude=None, include=None, | |
238 exclude_relations=None, include_relations=None, | |
239 include_methods=None): | |
240 """Returns a dictionary representing the fields of the specified `instance` | |
241 of a SQLAlchemy model. | |
242 | |
243 The returned dictionary is suitable as an argument to | |
244 :func:`flask.jsonify`; :class:`datetime.date` and :class:`uuid.UUID` | |
245 objects are converted to string representations, so no special JSON encoder | |
246 behavior is required. | |
247 | |
248 `deep` is a dictionary containing a mapping from a relation name (for a | |
249 relation of `instance`) to either a list or a dictionary. This is a | |
250 recursive structure which represents the `deep` argument when calling | |
251 :func:`!_to_dict` on related instances. When an empty list is encountered, | |
252 :func:`!_to_dict` returns a list of the string representations of the | |
253 related instances. | |
254 | |
255 If either `include` or `exclude` is not ``None``, exactly one of them must | |
256 be specified. If both are not ``None``, then this function will raise a | |
257 :exc:`ValueError`. `exclude` must be a list of strings specifying the | |
258 columns which will *not* be present in the returned dictionary | |
259 representation of the object (in other words, it is a | |
260 blacklist). Similarly, `include` specifies the only columns which will be | |
261 present in the returned dictionary (in other words, it is a whitelist). | |
262 | |
263 .. note:: | |
264 | |
265 If `include` is an iterable of length zero (like the empty tuple or the | |
266 empty list), then the returned dictionary will be empty. If `include` is | |
267 ``None``, then the returned dictionary will include all columns not | |
268 excluded by `exclude`. | |
269 | |
270 `include_relations` is a dictionary mapping strings representing relation | |
271 fields on the specified `instance` to a list of strings representing the | |
272 names of fields on the related model which should be included in the | |
273 returned dictionary; `exclude_relations` is similar. | |
274 | |
275 `include_methods` is a list mapping strings to method names which will | |
276 be called and their return values added to the returned dictionary. | |
277 | |
278 """ | |
279 30300 67166 2.2 0.6 if (exclude is not None or exclude_relations is not None) and \ | |
280 (include is not None or include_relations is not None): | |
281 raise ValueError('Cannot specify both include and exclude.') | |
282 # create a list of names of columns, including hybrid properties | |
283 30300 60188 2.0 0.5 try: | |
284 151200 628031 4.2 5.4 columns = [p.key for p in object_mapper(instance).iterate_properties | |
285 120900 298941 2.5 2.6 if isinstance(p, ColumnProperty)] | |
286 except UnmappedInstanceError: | |
287 return instance | |
288 #columns += [ x.__name__ for x in sqlalchemy_inspect(instance.__class__).all_orm_descriptors if | |
289 # x.extension_type == hybrid.HYBRID_PROPERTY ] | |
290 151500 347515 2.3 3.0 for parent in type(instance).mro(): | |
291 1272600 2791507 2.2 24.0 columns += [key for key, value in parent.__dict__.items() | |
292 1151400 2831103 2.5 24.3 if isinstance(value, hybrid_property)] | |
293 # filter the columns based on exclude and include values | |
294 30300 63958 2.1 0.5 if exclude is not None: | |
295 columns = (c for c in columns if c not in exclude) | |
296 30300 61327 2.0 0.5 elif include is not None: | |
297 columns = (c for c in columns if c in include) | |
298 # create a dictionary mapping column name to value | |
299 30300 668946 22.1 5.7 result = dict((col, getattr(instance, col)) for col in columns | |
300 if not (col.startswith('__') or col in COLUMN_BLACKLIST)) | |
301 # add any included methods | |
302 30300 69128 2.3 0.6 if include_methods is not None: | |
303 result.update(dict((method, getattr(instance, method)()) | |
304 for method in include_methods | |
305 if not '.' in method)) | |
306 # Check for objects in the dictionary that may not be serializable by | |
307 # default. Specifically, convert datetime and date objects to ISO 8601 | |
308 # format, and convert UUID objects to hexadecimal strings. | |
309 121200 299977 2.5 2.6 for key, value in result.items(): | |
310 # TODO We can get rid of this when issue #33 is resolved. | |
311 90900 253328 2.8 2.2 if isinstance(value, datetime.date): | |
312 result[key] = value.isoformat() | |
313 90900 233451 2.6 2.0 elif isinstance(value, uuid.UUID): | |
314 result[key] = str(value) | |
315 90900 2663623 29.3 22.9 elif is_mapped_class(type(value)): | |
316 result[key] = to_dict(value) | |
317 # recursively call _to_dict on each of the `deep` relations | |
318 30300 67388 2.2 0.6 deep = deep or {} | |
319 30600 81839 2.7 0.7 for relation, rdeep in deep.items(): | |
320 # Get the related value so we can see if it is None, a list, a query | |
321 # (as specified by a dynamic relationship loader), or an actual | |
322 # instance of a model. | |
323 300 11395 38.0 0.1 relatedvalue = getattr(instance, relation) | |
324 300 646 2.2 0.0 if relatedvalue is None: | |
325 result[relation] = None | |
326 continue | |
327 # Determine the included and excluded fields for the related model. | |
328 300 586 2.0 0.0 newexclude = None | |
329 300 572 1.9 0.0 newinclude = None | |
330 300 616 2.1 0.0 if exclude_relations is not None and relation in exclude_relations: | |
331 newexclude = exclude_relations[relation] | |
332 300 600 2.0 0.0 elif (include_relations is not None and | |
333 relation in include_relations): | |
334 newinclude = include_relations[relation] | |
335 # Determine the included methods for the related model. | |
336 300 587 2.0 0.0 newmethods = None | |
337 300 608 2.0 0.0 if include_methods is not None: | |
338 newmethods = [method.split('.', 1)[1] for method in include_methods | |
339 if method.split('.', 1)[0] == relation] | |
340 300 2003 6.7 0.0 if is_like_list(instance, relation): | |
341 300 683 2.3 0.0 result[relation] = [to_dict(inst, rdeep, exclude=newexclude, | |
342 include=newinclude, | |
343 include_methods=newmethods) | |
344 30300 84508 2.8 0.7 for inst in relatedvalue] | |
345 300 572 1.9 0.0 continue | |
346 # If the related value is dynamically loaded, resolve the query to get | |
347 # the single instance. | |
348 if isinstance(relatedvalue, Query): | |
349 relatedvalue = relatedvalue.one() | |
350 result[relation] = to_dict(relatedvalue, rdeep, exclude=newexclude, | |
351 include=newinclude, | |
352 include_methods=newmethods) | |
353 30300 61128 2.0 0.5 return result |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment