An App Loading mechanism for Django ==================================== About Me ---------- Hi everyone,
My name is Nick Sandford, I'm an electrical engineering student at the University of Western Australia. Background ----------- I haven't been a particularly active contributor to any open source project - here is where I hope to change that. In my current work at Christ Church Grammar School we use Django heavily for most of our internal projects. I've followed django-dev closely for a couple of years and I have poked around with its internals on various occasions. Plan ----- Implement an improved application loading mechanism into Django. Rationale --------- Django current application loading code is inflexible in many cases. There exists a need for a number of extra features to be added to the way applications are handled such as: * The ability to internationalise application names. * The ability to customise application names similar to ``verbose_name`` in ``model._meta`` * Deploy the same application multiple times in a single project. * Deploy two different applications with the same name. * Manage settings within applications. Method ------- I don't intend to solve the third dot point of the previous list - it seems like a difficult problem, possibly to be tackled post-GSoC. What I do intend to do is to move towards 'application classes' more akin to ``django.contrib.admin``. New syntax in ``settings.INSTALLED_APPS`` will be introduced to address the previous issues. Some examples of accepted syntax: .. sourcecode:: python INSTALLED_APPS = ( 'django.contrib.auth', app('blog.BlogApplication', 'blog_1', 'My blog', 'app1_'), app('blog.BlogApplication', 'blog_2', 'Some other blog', 'app2_'), app(path='tagging.Tagging', verbose_name='My tagging application'), app('categories', db_prefix='cat_'), app({'path': 'django.contrib.admin.AdminApplication', 'label': 'admin', 'verbose_name': 'Secret Admin'}), ) The ``app`` function will take four arguments, three of which are optional. These are ``path``, ``label``, ``verbose_name``, and ``db_prefix``. It will return an instance of an ``Application`` object, which will contain all of an installed application's information. ``path`` will be the dotted path to a subclass of ``Application``. The downside is that ``settings.py`` requires an import, which may be against style rules. .. sourcecode:: python def app(path, label=None, verbose_name=None, db_prefix='') if not path or not isinstance(path, basestring): raise ImproperlyConfigured('Application path must be string.') application_class = import_module(path) return application_class(path, label, verbose_name, db_prefix) ``INSTALLED_APPS`` will then be a tuple containing strings or ``Application`` instances. The application loading code will iterate over ``INSTALLED_APPS`` and construct an internal cache of ``Application`` instances to be used with ``get_models``, etc. For backwards compatibility, if an element of the tuple is a string, an instance of a base ``Application`` class will be created with sane defaults (similar to ``app_label`` at the moment). The ``Application`` class will be very similar to ``django.contrib.admin``'s ``AdminSite`` and will hopefully simplify application settings. If you write views and urls directly on the ``Application`` class itself, instead of an ``from django.conf import settings`` and subsequent ``settings.API_KEY``, you could just reference ``self.api_key`` for instance. This wouldn't be the required, just an optional extra. Model classes will get a ``_meta.app`` attribute, which will be an instance of the model's ``Application`` class. Models should only be associated with one application. I agree with moving ``django.db.models.loading`` to ``core.apps``, since we'll no longer require applications to have a ``models.py``. A reference to the new functions in ``core.apps`` will still live in ``django.db.models.loading`` for backwards compatibility. A subclass of ``Application`` might look like: .. sourcecode:: python from django.views.simple import direct_to_template from djang.core.apps import Application from blog.models import Entry, Category class BlogApplication(Application): models = [Entry, Category] api_key = 'default' def entry_detail(self, slug, request, template_name='blog/entry_detail.html'): entry = get_object_or_404(Entry, slug=slug) context = { 'entry': entry, 'api_key': self.api_key, } return direct_to_template(request, template_name, context) Hurdles -------- There are a list of possible technical issues: * Introducing the new ``app`` function requires an import in settings.py which might not be acceptable behaviour. * Two applications with the same label. * Worrying amounts of things that may affect backwards compatibility would probably need addressing. Solutions ---------- We could alternatively introduce a new file into the project, ``applications.py`` which contains purely application-related setup. This might be handy to manage application settings and to ensure ``settings.py`` doesn't get too full of application-specific settings. This could allow us do something like: .. sourcecode:: python from django.core import apps from blog import BlogApplication class MyBlogApplication(BlogApplication): api_key = 'testing' another_blog = BlogApplication(label='blog2', verbose_name=_('Another blog'), api_key='anothertest') apps.register(MyBlogApplication, label='blog', verbose_name=_('My blog')) apps.register(another_blog) depending on what people would like more. This could allow us not to touch ``settings.INSTALLED_APPS`` at all. To solve the 'two applications named auth' problem, the ``AppCache`` keeps track of application instances, not ``app_label``. For the case of two applications with the same name, ``get_app`` should return a tuple containing both application instances with that name. To ensure a single application instance is returned with ``get_app``, another argument - ``path`` should be added. ``get_models`` and ``get_model`` would take an application instance and return models on that instance. This might affect the admin's handling of applications. Timeline --------- 1) Implement the ``Application`` class. -- 2 weeks 2) Move ``django.db.models.loading`` to ``django.core.apps`` and refactor ``get_app``, ``get_model``, etc. -- 1 week 3) Modify the admin, management, translation, templatetags, templateloaders to use ``app.path`` -- 1 week 4) Testing and documentation -- 3 weeks 5) Bug fixes and backwards incompatibility problems -- 1 week 6) Time permitting possibly tackle the multiple instances of the same app problem. (about 2 weeks). Any feedback would be greatly appreciated, sorry for the late application and good luck to all the other applicants :) Thanks, Nick -- You received this message because you are subscribed to the Google Groups "Django developers" group. To post to this group, send email to django-develop...@googlegroups.com. To unsubscribe from this group, send email to django-developers+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.