Created
January 13, 2014 11:47
-
-
Save andir/8398978 to your computer and use it in GitHub Desktop.
flask-restless to_dict sqlalchemy inspection 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
[3.315706968307495, 3.330582857131958, 3.3374509811401367] | |
Timer unit: 1e-06 s | |
File: [..]/flask_restless/helpers.py | |
Function: to_dict at line 237 | |
Total time: 6.60634 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 66252 2.2 1.0 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 59505 2.0 0.9 try: | |
284 151200 597344 4.0 9.0 columns = [p.key for p in object_mapper(instance).iterate_properties | |
285 120900 292212 2.4 4.4 if isinstance(p, ColumnProperty)] | |
286 except UnmappedInstanceError: | |
287 return instance | |
288 181800 801350 4.4 12.1 columns += [ x.__name__ for x in sqlalchemy_inspect(instance.__class__).all_orm_descriptors if | |
289 151500 339713 2.2 5.1 x.extension_type == hybrid.HYBRID_PROPERTY ] | |
290 #for parent in type(instance).mro(): | |
291 # columns += [key for key, value in parent.__dict__.items() | |
292 # if isinstance(value, hybrid_property)] | |
293 # filter the columns based on exclude and include values | |
294 30300 62787 2.1 1.0 if exclude is not None: | |
295 columns = (c for c in columns if c not in exclude) | |
296 30300 60372 2.0 0.9 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 615233 20.3 9.3 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 68745 2.3 1.0 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 290594 2.4 4.4 for key, value in result.items(): | |
310 # TODO We can get rid of this when issue #33 is resolved. | |
311 90900 247336 2.7 3.7 if isinstance(value, datetime.date): | |
312 result[key] = value.isoformat() | |
313 90900 228062 2.5 3.5 elif isinstance(value, uuid.UUID): | |
314 result[key] = str(value) | |
315 90900 2570737 28.3 38.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 65728 2.2 1.0 deep = deep or {} | |
319 30600 79231 2.6 1.2 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 12220 40.7 0.2 relatedvalue = getattr(instance, relation) | |
324 300 651 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 573 1.9 0.0 newexclude = None | |
329 300 575 1.9 0.0 newinclude = None | |
330 300 620 2.1 0.0 if exclude_relations is not None and relation in exclude_relations: | |
331 newexclude = exclude_relations[relation] | |
332 300 614 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 584 1.9 0.0 newmethods = None | |
337 300 601 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 1804 6.0 0.0 if is_like_list(instance, relation): | |
341 300 644 2.1 0.0 result[relation] = [to_dict(inst, rdeep, exclude=newexclude, | |
342 include=newinclude, | |
343 include_methods=newmethods) | |
344 30300 81880 2.7 1.2 for inst in relatedvalue] | |
345 300 585 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 59790 2.0 0.9 return result |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment