simonw / djng
- Source
- Commits
- Network (8)
- Issues (1)
- Downloads (0)
- Wiki (1)
- Graphs
-
Tree:
953eb33
djng / services_api_ideas.txt
| c892dddf » | simonw | 2009-05-18 | 1 | Services API | |
| 2 | ============ | ||||
| 3 | |||||
| 4 | Requirements: | ||||
| 5 | |||||
| 6 | - Maintain a stack of implementations for each service | ||||
| 7 | - Only one implementation of a service is "active" at a time | ||||
| 8 | - The default API for a service uses the current active implementation | ||||
| 9 | - Implementations can be used without participating in the stack at all | ||||
| 10 | - Middleware can temporarily push a new service on to the stack, for the | ||||
| 11 | duration of the current request | ||||
| 12 | - Services temporarily pushed on to the stack are reliably popped off again | ||||
| 13 | at the end of the current request, even if an exception is raised | ||||
| 14 | |||||
| 15 | It would be nice if the solution meant that the current Django APIs for things | ||||
| 16 | like accessing the cache or loading a template could remain backwards | ||||
| 17 | compatible. | ||||
| 18 | |||||
| 19 | Some ideas | ||||
| 20 | ---------- | ||||
| 21 | |||||
| 22 | # Configure the default service (at the bottom of the stack) | ||||
| 23 | djng.template.configure(template_dirs = ('templates/default',)) | ||||
| 24 | |||||
| 25 | # Reconfigure for part of the URL space | ||||
| 26 | app = djng.Router( | ||||
| 27 | (r'^foo', djng.reconfigure( | ||||
| 28 | foo_view, djng.template, | ||||
| 29 | template_dirs = ('templates/foo', 'templates/default') | ||||
| 30 | )), | ||||
| 31 | (r'^bar', bar_view), | ||||
| 32 | ) | ||||
| 33 | |||||
| 34 | djng.reconfigure is middleware which wrapes foo_view, then duplicates the | ||||
| 35 | current djng.template service and applies a new template_dirs property to it , | ||||
| 36 | based on keyword argument. | ||||
| 37 | |||||
| 38 | Or... use a decorator: | ||||
| 39 | |||||
| 40 | app = djng.Router( | ||||
| 41 | (r'^foo', djng.reconfigure( | ||||
| 42 | djng.template, template_dirs = ('templates/foo', 'templates/default') | ||||
| 43 | )(foo_view)), | ||||
| 44 | (r'^bar', bar_view), | ||||
| 45 | ) | ||||
| 46 | |||||
| 47 | Which could also be written: | ||||
| 48 | |||||
| 49 | @djng.reconfigure( | ||||
| 50 | djng.template, template_dirs = ('templates/foo', 'templates/default') | ||||
| 51 | ) | ||||
| 52 | def foo_view(request): | ||||
| 53 | # ... | ||||
| 54 | |||||
| 55 | Reconfigure is a bit strange though, because the majority of services will | ||||
| 56 | probably want a completely new implementation rather than a tweak to the | ||||
| 57 | existing one. Caching is a good example: | ||||
| 58 | |||||
| 59 | # Set the default cache to be an InMemoryCache | ||||
| 60 | djng.cache.configure(djng.cache.InMemoryCache()) | ||||
| 61 | |||||
| 62 | # One URL path gets to use memcache instead | ||||
| 63 | app = djng.Router( | ||||
| 64 | (r'^foo', djng.reconfigure( | ||||
| 65 | foo_view, djng.cache, djng.cache.Memcache('127.0.0.1:11221') | ||||
| 66 | )), | ||||
| 67 | (r'^bar', bar_view), | ||||
| 68 | ) | ||||
| 69 | |||||
| 70 | Or as a decorator: | ||||
| 71 | |||||
| 72 | app = djng.Router( | ||||
| 73 | (r'^foo', djng.reconfigure( | ||||
| 74 | djng.cache, djng.cache.Memcache('127.0.0.1:11221') | ||||
| 75 | )(foo_view)), | ||||
| 76 | (r'^bar', bar_view), | ||||
| 77 | ) | ||||
| 78 | |||||
| 79 | The signature of djng.reconfigure feels a bit strange though: | ||||
| 80 | |||||
| 81 | def reconfigure( | ||||
| 82 | service_to_reconfigure, | ||||
| 83 | [optional new_service_instance], | ||||
| 84 | **reconfigure_kwargs | ||||
| 85 | ): | ||||
| 86 | # ... | ||||
| 87 | |||||
| 88 | Internally, reconfigure uses a try/finally block to ensure that the altered | ||||
| 89 | service implementation pushed on to the stack is popped off by the end of the | ||||
| 90 | request. | ||||
