On Thu, 2006-10-19 at 05:27 -0700, MerMer wrote:
> Malcom, many thanks.
> 
> I have to admit as a newbie to Python and Django and I dont' fully
> understand how "import" works.  I just presumed that you put a
> reference to any module at the top.

You can. But you aren't referring to a module, you are referring to
something inside the module's namespace (the Review model object). The
difference is important.

> At the top of the product.models.py file I have the following:-
> 
> "from mysite.promotions.signals import update_review_average"

Welcome to the world of recursive imports.

The quick fix here is to replace that line with 

        from mysite.promotions import signals

and you will be fine.

To understand what is happening (this is more comp.lang.python
territory, but one post won't hurt), think about what is happening at
the Python level here:

Step #1: Python imports your models file. It opens the file, makes a
note that it is about to create a new module called "product.models" and
then starts reading the file one line at a time. It does this by putting
an entry in the sys.modules dictionary with the key as the name of the
module and the value being an empty module object, which it will then
fill in as it parses the file.

Step #2: very early on in the models file it finds a line to import some
stuff from signals.

Step #3: Python stops processing products.models and starts importing
signals. it opens up the signals.py file, makes a note that it is
creating a new module (another entry in sys.modules) and starts reading
it one line at a time.

Step #4: It encounters the line in signals.py that says "import some
stuff from models.py". Now the fun begins. Python looks in its
dictionary of modules (sys.modules) and sees an entry for product.models
already (it has this entry do that it doesn't get stuck in loops or try
to import a module more than once). However, this product.models entry
points to a currently empty module (since Python has not yet finished
importing it in step #2 -- you told it to go off and process signals
first). Because you want something very specific from models.py, Python
raises an error (that very specific thing ("Review") does not exist in
the empty model.

Now, you can work around this by either (a) not having circular imports
(they often suggest a much tighter coupling than you intended in any
case), or (b) only importing the module name, not a specific thing from
that module.

If you had "from product import models" in signals.py, then in step #4,
above, Python would see that it had already imported (or started to
import) product.models and continue on happily. Later, after everything
had finished importing, you could refer to models.Review inside
signals.py and it would work (because the "models" module would be fully
imported). You could not refer to models.Review outside of a function in
signals.py, because you would hit the circular import problem again, but
inside functions (which aren't executed until you call them -- well
after import time), you could be fine.

Note that this is not a problem with Django. It is a fairly natural
consequence of using a language that allows dynamic imports and name
bindings (e.g. Python) and only wants to import things once at most. It
would be possible for Python to work around this problem in some cases,
but not always, in general. Once you understand the import process
outlined above, it is usually fairly easy to work out how to avoid such
import problems.

Regards,
Malcolm


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To post to this group, send email to django-users@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/django-users
-~----------~----~----~----~------~----~------~--~---

Reply via email to