To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/1E8B5E64-64A1-4561-A1F1-0FDD59D5336A%40polytechnique.org.--
You received this message because you are subscribed to the Google Groups "Django developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers.
For more options, visit https://groups.google.com/groups/opt_out.
On 30 déc. 2013, at 13:29, Aymeric Augustin <aymeric....@polytechnique.org> wrote:
[...]
The real question — is requiring django.setup() acceptable? Explicit is better than implicit, after all…
I would suggest that Anssi's issues with model loading ordering are helped best by having `django.setup()` and doing away with the magical "I created a Model subclass and my app registry hot populated" issues. The proposed solution 2a seems best to me. It has never been clear how Django initialised and used a variety of dark magic (strange postponing, pythonpath manipulation and a freaking borg pattern!), and if the best way to make this explicit is to, well, require an explicit setup() call, then this is even better.
As an aside, these changes seem to me to make it easier to make things less global. A Django project (to use our traditional terminology) consists of some settings, which determine an instance of the app registry (and a load of apps inside it). The more isolated these become, the easier it seems to get a separate bunch of settings somewhere with different app registry at the same time. Obviously we still have the issue that everything assumes there is a canonical version of settings in Django.conf, but there may well be a way to remove a lot of settings with app configs.
Marc
--
You received this message because you are subscribed to the Google Groups "Django developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/514e3b88-329e-43e7-a88b-93a75f735573%40googlegroups.com.
On another note, if you're going to muck about with a model in an existing app (perhaps for a very good reason like Permission) the best way of doing that (IMO) would be to create a subclassed AppConfig, get the relevant model from Apps in the setup() method and modify it directly there (add fields, change a fields max_length etc.)
If this pattern is OK with your design Aymeric then it may even be worth documenting at some point, at risk of encouraging hacks. It's a much more elegant way to have dynamic cms models than has ever existed before though.
doing away with the magical "I created a Model subclass and my app registry hot populated" issues.
On another note, if you're going to muck about with a model in an existing app (perhaps for a very good reason like Permission) the best way of doing that (IMO) would be to create a subclassed AppConfig, get the relevant model from Apps in the setup() method and modify it directly there (add fields, change a fields max_length etc.
If this pattern is OK with your design Aymeric then it may even be worth documenting at some point, at risk of encouraging hacks. It's a much more elegant way to have dynamic cms models than has ever existed before though.
Heh, I forgot that contribute to class isn't documented. On second thoughts, let's not document this unless we actually have a good API for it.
--
You received this message because you are subscribed to the Google Groups "Django developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/899C8193-543D-4DF4-8435-8099FB6770C3%40polytechnique.org.
Hello,
There’ve been lots of brainstorming on this topic. It is now tracked in this ticket: https://code.djangoproject.com/ticket/21676. I’ve also sent a pull request: https://github.com/django/django/pull/2128.
There’s a consensus on the general idea:
- AppConfigs are a good place for startup code,
- that code should be called when the app registry gets populated,
- the app registry should be populated as early as possible.
But the details are tricky. Specifically there are two problems for which a design decision must be made. I need your feedback.
### Problem 1 — Designing the API
I’d like to make the API as simple as possible, which means:
class AppConfig(object):
# …
def setup(self):
“””Override this method in subclasses to run code when Django starts.”””
Logically, this would get called when the app cache is fully populated. Running user code while the app cache isn’t ready will backfire.
But at this point it’s too late to register listeners for the `class_prepared` signal, so we need an early entry point. I believe AppConfig.__init__ does the job.
I originally suggested apps_ready() and models_ready() but I wasn’t happy with this solution because it leaks internal implementation details and inflicts a needlessy complicated API on the end users.
Relevant commits in the pull request: “Added AppConfig.setup() to run setup code.” and “Updated advice on connecting signals at startup."
## Solution 2.a — Require users to call django.setup() before they use the ORM. setup() would configure the settings and populate the app registry.
It’s easy to implement a deprecation path. It’s just a matter of raising a warning whenever an app registry method is called while the app registry isn’t populated. Eventually this should raise an exception.
As a nice side effect, this allows us to decouple django.apps from django.conf entirely, helping our guerrilla against global state. The value of INSTALLED_APPS would always be passed explicitly to populate_apps(installed_apps).
I’m currently working on this and I’ll add a commit to the pull request (which I’ll remove if we go for solution 2.b).
## Solution 2.b — Keep the current behavior.
Barring an explicit function call, I can’t think of a way to populate the app registry before any user code runs in this scenario without getting into circular imports. Populating when importing django.apps.registry makes `from django.apps import apps` unsafe. Populating when creating the first model class immediately creates a loop.
If we can’t guarantee the app registry is populated on startup, we’d better keep the current behavior. Moving the population arbitrarily earlier would introduce action at a distance.
If we chose this solution, it would be interesting to review all uses of get_models(), examine which ones can assume the app registry is populated and which one can’t, and figure out if there’s room for refactoring.
## Solution 2.a — Require users to call django.setup() before they use the ORM. setup() would configure the settings and populate the app registry.
On Mon, Dec 30, 2013 at 8:29 PM, Aymeric Augustin <aymeric....@polytechnique.org> wrote:
Logically, this would get called when the app cache is fully populated. Running user code while the app cache isn’t ready will backfire.
But at this point it’s too late to register listeners for the `class_prepared` signal, so we need an early entry point. I believe AppConfig.__init__ does the job.
An idle thought -- this problem is caused because the class_prepared signal is currently being issued at the end of ModelBase.__new__(). Is this signal location actually a requirement? Is there any reason that the prepare signal couldn't be decoupled from __new__(), and be issued at the end of app configuration (at some appropriate point in the process)? We'd need to be careful about exactly *when* the signal was issued, and what order signals were issued to make sure ordering doesn't change too drastically between releases -
I considered populating the app registry when the settings are configured i.e. when the first setting is accessed or settings.configure() is called but I decided against it:
- There’s no good reason for django.conf to know about django.apps.
- The risk of creating circular imports is very high: one doesn’t expect `settings.FOO` to import all applications and models.
- It may not solve this use case; nothing guarantees that the settings will be accessed before using the ORM.I'm not sure I'm completely convinced about this.I'll pay the argument that there's no good reason (from an architectural perspective) for conf to know about apps -- *unless* you're taking the view that the configuring settings *is* what passes for Django's setup sequence. There's an argument to be made that this is already the case - logging is configured as a consequence of accessing settings, for example, and this logic was put in settings specifically because configuring settings is the closest we come to a "first mover" event in the Django stack.
Is this what you would expect -- well, I suppose that comes down to what is documented. I don't think it's prima facie surprising that a method called "configure", that has access to lists of installed apps, models, logging and i18n configurations, will have the side effect of importing and configuring those modules/objects; and if the documentation says that this is what it does, then all the better.
Circular imports are obviously an issue we want to avoid - but I'm not sure how you would manufacture a circular import here. Django settings are essentially just constants plus some path joining, with some laziness thrown in; I'm not sure how you'd manufacture circular imports going through the settings layer.
To my mind, there's value in keeping the entry point we already have unless there's a major architectural reason to do otherwise. However, I'm not fundamentally opposed to introducing a new, clean entry point whose mandate is very specifically "set things up".
On 31 déc. 2013, at 04:28, Russell Keith-Magee <rus...@keith-magee.com> wrote:
On Mon, Dec 30, 2013 at 8:29 PM, Aymeric Augustin <aymeric....@polytechnique.org> wrote:
Logically, this would get called when the app cache is fully populated. Running user code while the app cache isn’t ready will backfire.
But at this point it’s too late to register listeners for the `class_prepared` signal, so we need an early entry point. I believe AppConfig.__init__ does the job.
An idle thought -- this problem is caused because the class_prepared signal is currently being issued at the end of ModelBase.__new__(). Is this signal location actually a requirement? Is there any reason that the prepare signal couldn't be decoupled from __new__(), and be issued at the end of app configuration (at some appropriate point in the process)? We'd need to be careful about exactly *when* the signal was issued, and what order signals were issued to make sure ordering doesn't change too drastically between releases -
That’s an interesting idea. To be honest, I’ve shied away from touching ModelBase.__new__ — a 230 line method in a metaclass, what could possibly go wrong? ;-)
In almost all cases AppConfig.setup() will be early enough. class_prepared is the only exception I found. I’m not sure what it’s designed for (nor that it’s a good idea at all).
On 30 déc. 2013, at 21:59, Marc Tamlyn <marc....@gmail.com> wrote:On another note, if you're going to muck about with a model in an existing app (perhaps for a very good reason like Permission) the best way of doing that (IMO) would be to create a subclassed AppConfig, get the relevant model from Apps in the setup() method and modify it directly there (add fields, change a fields max_length etc.
Yes, it’s simple, and I’m quite confident it would work:
from django.apps import AppConfig
class CustomAuthConfig(AppConfig):name = “django.contrib.auth”def setup(self):Permission = self.get_model('Permission’)# twiddle Permission
--
You received this message because you are subscribed to the Google Groups "Django developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-developers+unsubscribe@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/52C29D0E.3080203%40thl.fi.
Git clean -fdx
I had the same problem the other day.
--
You received this message because you are subscribed to the Google Groups "Django developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/ed241825-b064-49ca-a9de-d527c1851907%40googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/CAGdCwBt_aRMmm0q44Nj301nVNL84RfjXHbym2QW8-GA%2BXyBtTA%40mail.gmail.com.