Changes between Version 15 and Version 16 of new_meta_api


Ignore:
Timestamp:
Jul 11, 2014, 8:32:45 AM (10 years ago)
Author:
pirosb3
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • new_meta_api

    v15 v16  
    257257The downsides if this aspect is that we cache a bit more naively (there are less layers of caching) but benchmarks show this does not
    258258decrease performance.
     259
     260==== Used internal caching instead of lru_cache
     261Our first approach to caching was to use functools.lru_cache. lru_cache is a simple decorator that provides cache and an expiry function
     262built-it. It worked correctly with the new API but cProfile quickly showed how a lot of computing time was done inside lru_cache itself.
     263
     264The decision taken was to do very caching with simple try / catch and a dictionary for memoizing. This is also because we really don't need
     265the 'lru' part of 'lru_caching': there are only a finite number of combinations that can be called.
     266
     267==== Used internal caching instead of lru_cache
     268Our first approach to caching was to use functools.lru_cache. lru_cache is a simple decorator that provides cache and an expiry function
     269built-it. It worked correctly with the new API but cProfile quickly showed how a lot of computing time was done inside lru_cache itself.
     270
     271The decision taken was to do very caching with simple try / catch and a dictionary for memoizing. This is also because we really don't need
     272the 'lru' part of 'lru_caching': there are only a finite number of combinations that can be called.
     273
     274==== Use cached_properties when possible
     275Function calls are expensive in Python, All sensible attributes with no arguments have been transformed into cached_properties.
     276A cached property is a read-only property that is calculated on demand and automatically cached. If the value has already been calculated,
     277the cached value is returned. Cached properties avoid a new stack and are used for fast-access to fields, concrete_fields,
     278local_concrete_fields, many_to_many, field_names
     279
     280==== enabled m2m fields by default on get_field
     281The old get_field API was defined as follows:
     282
     283{{{
     284    def get_fields(self, field_name, many_to_many=True)
     285}}}
     286
     287Our first iteration of the API was to refactor this as
     288
     289{{{
     290    def get_fields(self, field_name, include_related=True)
     291}}}
     292
     293This was done for 2 reasons:
     2941) We managed to squash 2 functions (get_field and get_field_by_name) in 1 single call
     2952) I could not find any reason for the many_to_many flag to exist! there can never be data and m2m fields with the same name. So this looked
     296like a legacy parameter that didn't have any effect (because turning it off did not break any tests)
     297
     298Finally, the reason the many_to_many flag existed was for a special validation case that was not documented anywhere. Russell helped me in
     299looking for edge cases and finally I came up with a failing test case: https://github.com/django/django/pull/2893. The test case would fail on the
     300new API but succeed on master.
     301
     302Our final iteration was to add all the field types as flags to get_field. By making m2m as first parameter, we avoid breaking existing implementations
     303and maintain a similarity with the 'get_fields' API.
Back to Top