An updated proposal:
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``.
I plan to introduce a new file into the project structure - ``apps.py`` which
will be used to register installed applications with the ``AppCache``. I will
also move to introduce a new setting in ``settings.py``, ``APP_LOADER`` which
will be a string containing a dotted path to an application loading class. This
will serve to facilitate a move from ``settings.INSTALLED_APPS`` to the new
``apps.py``. ``APP_LOADER`` will take one of two values:
'django.core.apps.loader.legacy', which will use ``settings.INSTALLED_APPS`` or
'django.core.apps.loader.registry', which would use the new registry-based
approach. Only applications registered in ``apps.py`` in the project directory
will be registered with the ``AppCache``. The default APP_LOADER setting for
1.3 will be 'django.core.apps.loader.legacy'.
``apps.py`` will contain purely application-related setup. This should be handy
to manage application settings and to ensure ``settings.py`` doesn't get too
full of application-specific settings. This will allow us to register an app
in one of three ways 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')
# an application class.
apps.register(MyBlogApplication, label='blog', verbose_name=_('My blog'))
# an application instance.
apps.register(another_blog)
# old-style application.
apps.register('django.contrib.auth')
This could allow us not to touch ``settings.INSTALLED_APPS`` at all. If people
need to iterate over ``settings.INSTALLED_APPS``, a move to ``get_apps`` will
be recommended.
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.
In addition to providing application settings an ``Application`` will be
required to explicitly define their models. These models could live outside
the traditional application structure, provided they are included in the
``models`` list on ``Application``. The current structure promotes strictly
requiring models for an application to reside in that application's
``models.py``. I wouldn't be promoting changing the current status quo with
regard to this, but it would be possible to deviate from it and include models
defined outside of the applications ``models.py`` on an ``Application``.
An application class would have other benefits, as evidenced by a short look at
``django.contrib.admin.AdminSite``. It could concievably be used to define a
set of 'base' add/edit/delete views for each model on an ``Application``. It
could even be used to set up an application's urls. This could make an
``Application`` class unwieldy and large however, so it won't be forced and
people can continue using views.py and urls.py as before.
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.
There are a number of places within Django that rely on ``app_label`` and
that will need to be addressed. Ticket #3591 has patches that at least outline
areas that need changing, and the InstalledAppRevision wiki page is also quite
helpful. A non-exhaustive list of areas that need changing are: admin app
display name, admin permissions prefix, db table creation prefix, fixture
loading code, ``Model.Meta.app_label``, ``RelatedObject`` cross-app
identification, ``contrib.contenttypes``. There are also a number of places
that use string paths from ``settings.INSTALLED_APPS`` that should be simple to
change over.
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='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, context)
Hurdles
--------
There are a list of possible technical issues:
* Two applications with the same label.
* Registration of an app.
* Better handling of 'startup tasks'
* Worrying amounts of things that may affect backwards compatibility would
probably need addressing.
Solutions
----------
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.
Registration of an application is mentioned above, but it isn't a solved
problem and it needs work. With a deadline looming, all I can do is assure you
that I am committed to solving the problem as generically as possible. This
could pave the way for admin/signal/logging etc registration to become simpler.
Better handling of startup tasks would be investigated and addressed if
possible during the refactoring of ``AppCache`` and its associated functions.
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. -- 3 weeks
3) Modify the admin, management, translation, templatetags, templateloaders
to use ``app.path`` -- 2 weeks
4) Testing and documentation -- 3 weeks
5) Bug fixes and backwards incompatibility problems -- 1 week
I have exams early June, so my availablity during that time will be minimal.
I apologise for lumping "Testing and documentation" together, but if I didn't
include them like that, someone might question if there is any of it going on
at all. 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 [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/django-developers?hl=en.