[Soc2014] The new Options API

# Main API
Official Wiki page: https://code.djangoproject.com/wiki/new_meta_api

get_fields(m2m, data, related_m2m, related_objects, virtual,
include_parents, include_non_concrete, include_hidden, include_proxy) -> (field, field, ...)

get_field(field_name, m2m, data, related_m2m, related_objects, virtual) -> field

# Cached properties for fast access
fields -> (field, field, ..)
concrete_fields -> (field, field, ...)
local_concrete_fields -> (field, field, ...)
field_names (field_name, field_name, ..)

# Benchmarks
(compared to master)

| Benchmark Name | Control | Experiment | Diff |
| -------------- | ------- | ---------- | ---- |
| url_resolve_flat_i18n_off | 0.3224664569 | 0.3128736854 | 0.0095927715 (2.97% faster) |
| url_resolve_flat | 0.2262115002 | 0.2201457143 | 0.0060657859 (2.68% faster) |
| query_prefetch_related | 0.1185187101 | 0.1131614804 | 0.0053572297 (4.52% faster) |
| query_all | 0.0260368466 | 0.0244047880 | 0.0016320586 (6.27% faster) |
| query_select_related | 0.0590585470 | 0.0582756639 | 0.0007828832 (1.33% faster) |
| query_raw | 0.0150311589 | 0.0149269700 | 0.0001041889 (0.69% faster) |
| query_distinct | 0.0003427148 | 0.0003322124 | 0.0000105023 (3.06% faster) |
| url_resolve | 0.0174066782 | 0.0174011946 | 0.0000054836 (0.03% faster) |
| template_render_simple | 0.0001164556 | 0.0001118183 | 0.0000046372 (3.98% faster) |
| query_delete_related | 0.0003562689 | 0.0003521204 | 0.0000041485 (1.16% faster) |
| form_create | 0.0001154184 | 0.0001116633 | 0.0000037551 (3.25% faster) |
| model_creation | 0.0002620935 | 0.0002592921 | 0.0000028014 (1.07% faster) |
| query_iterator | 0.0002910018 | 0.0002886057 | 0.0000023961 (0.82% faster) |
| form_clean | 0.0000283957 | 0.0000273466 | 0.0000010490 (3.69% faster) |
| url_resolve_nested | 0.0001253605 | 0.0001250029 | 0.0000003576 (0.29% faster) |
| query_delete | 0.0002635837 | 0.0002634764 | 0.0000001073 (0.04% faster) |
| raw_sql | 0.0000513077 | 0.0000515938 | -0.0000002861 (0.56% slower) |
| template_render | 0.0123201489 | 0.0123205304 | -0.0000003815 (0.00% slower) |
| query_none | 0.0001389146 | 0.0001396894 | -0.0000007749 (0.56% slower) |
| query_all_multifield | 0.0442516685 | 0.0442527294 | -0.0000010610 (0.00% slower) |
| multi_value_dict | 0.0001797199 | 0.0001827717 | -0.0000030518 (1.70% slower) |
| query_count | 0.0002346754 | 0.0002384424 | -0.0000037670 (1.61% slower) |
| locale_from_request | 0.0008673787 | 0.0008715868 | -0.0000042081 (0.49% slower) |
| query_exclude | 0.0005133271 | 0.0005178809 | -0.0000045538 (0.89% slower) |
| query_latest | 0.0003925323 | 0.0003977776 | -0.0000052452 (1.34% slower) |
| model_delete | 0.0004462004 | 0.0004532099 | -0.0000070095 (1.57% slower) |
| query_order_by | 0.0003699422 | 0.0003770232 | -0.0000070810 (1.91% slower) |
| query_aggregate | 0.0003185034 | 0.0003258467 | -0.0000073433 (2.31% slower) |
| default_middleware | 0.0004270792 | 0.0004346967 | -0.0000076175 (1.78% slower) |
| query_filter | 0.0004306793 | 0.0004388094 | -0.0000081301 (1.89% slower) |
| query_update | 0.0002333641 | 0.0002430677 | -0.0000097036 (4.16% slower) |
| query_in_bulk | 0.0004901409 | 0.0005011201 | -0.0000109792 (2.24% slower) |
| query_dates | 0.0005465746 | 0.0005576730 | -0.0000110984 (2.03% slower) |
| query_annotate | 0.0006684303 | 0.0006795764 | -0.0000111461 (1.67% slower) |
| query_values | 0.0003065467 | 0.0003197312 | -0.0000131845 (4.30% slower) |
| query_complex_filter | 0.0001333117 | 0.0001471758 | -0.0000138640 (10.40% slower) |
| query_values_list | 0.0002993703 | 0.0003140211 | -0.0000146508 (4.89% slower) |
| template_compilation | 0.0005861163 | 0.0006127477 | -0.0000266314 (4.54% slower) |
| query_get_or_create | 0.0013090134 | 0.0013397813 | -0.0000307679 (2.35% slower) |
| l10n_render | 0.0063407421 | 0.0063731670 | -0.0000324249 (0.51% slower) |
| query_exists | 0.0009287477 | 0.0009753466 | -0.0000465989 (5.02% slower) |
| qs_filter_chaining | 0.0008348227 | 0.0009381652 | -0.0001033425 (12.38% slower) |
| query_raw_deferred | 0.0182870388 | 0.0186469555 | -0.0003599167 (1.97% slower) |
| model_save_new | 0.0142104745 | 0.0145826817 | -0.0003722072 (2.62% slower) |
| model_save_existing | 0.0140855193 | 0.0145498991 | -0.0004643798 (3.30% slower) |
| query_get | 0.0273179531 | 0.0280359745 | -0.0007180214 (2.63% slower) |
Sum of all benchmarks (bigger is better): 0.0212707281
The approach you've taken here is:
 * Cache the result of get_fields() for a specific set of arguments
 * look up a name in that list; 
 * Raise FieldDoesNotExist if the name is not found.
The other obvious approach I can think of would be:
 * Cache a list of *all* fields
 * Look up the name in that list
 * Raise FieldDoesNotExist if the name is not found
 * Raise FieldDoesNotExist if the field doesn't have the requested properties.
I'd be interested to see the "memory vs speed" tradeoff for these two approaches.