Inconsistency when importing views and models

31 views
Skip to first unread message

jorr...@gmail.com

unread,
Jun 19, 2015, 9:11:34 PM6/19/15
to django...@googlegroups.com
This is mostly a cosmetic question, and I could be completely wrong because I'm fairly new to Django, or it could be that there is a perfectly logical explanation for this, but here goes:

It seems the code required to import views in urls.py and models in views.py is inconsistent (and in the case of urls.py perhaps redudant).

To import views in urls.py I have to use

from <appname> import views

...while in views.py I can simply write

from models import *

Why do I need to reference the appname in urls.py but not in views.py? Or is there a reason for this?

Mike Dewhirst

unread,
Jun 19, 2015, 9:55:05 PM6/19/15
to django...@googlegroups.com
On 20/06/2015 11:01 AM, jorr...@gmail.com wrote:
> This is mostly a cosmetic question, and I could be completely wrong
> because I'm fairly new to Django, or it could be that there is a
> perfectly logical explanation for this, but here goes:
>
> It seems the code required to import views in urls.py and models in
> views.py is inconsistent (and in the case of urls.py perhaps redudant).

Not really. It is pure Python and nothing to do with Django.

It depends on your project layout. For example, is models a directory or
a file?

Where is views.py?

Are you using absolute_import or relative import?

How does it work from within Python running in a terminal?

If things work inconsistently it probably means you are successfully
importing something which is on sys.path which you didn't expect.

hth

Mike
>
> To import views in urls.py I have to use
>
> |
> from<appname>importviews
> |
>
> ...while in views.py I can simply write
>
> |
> frommodels import*
> |
>
> Why do I need to reference the appname in urls.py but not in views.py?
> Or is there a reason for this?
>
> --
> You received this message because you are subscribed to the Google
> Groups "Django users" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to django-users...@googlegroups.com
> <mailto:django-users...@googlegroups.com>.
> To post to this group, send email to django...@googlegroups.com
> <mailto:django...@googlegroups.com>.
> Visit this group at http://groups.google.com/group/django-users.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/django-users/03eb4740-6503-4757-ae09-9183ac2b8502%40googlegroups.com
> <https://groups.google.com/d/msgid/django-users/03eb4740-6503-4757-ae09-9183ac2b8502%40googlegroups.com?utm_medium=email&utm_source=footer>.
> For more options, visit https://groups.google.com/d/optout.

Peith Vergil

unread,
Jun 19, 2015, 10:32:46 PM6/19/15
to django...@googlegroups.com

It depends on how your project files are structured. If you have a file structure that looks like this:

app/
    __init__.py
    models.py
    views.py
    urls.py

Then, you can simply use relative imports.

In views.py:
from models import *

In urls.py:
from views import *

If, for example, your models live in a separate Django app (i.e. a separate Python package):

app1/
    __init__.py
    views.py
    urls.py
app2/
    __init__.py
    models.py

Then, you have to import your models using its full path so Python will know where to look for it.

In app1/views.py:
from app2.models import *

You should familiarize yourself on how Python imports work since this is more of a Python issue rather than a Django issue.

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.

James Schneider

unread,
Jun 20, 2015, 1:42:01 AM6/20/15
to django...@googlegroups.com

This is strictly a Python question, nothing Django-specific, but I've found this site to be helpful in explaining the different ways to import things:

http://effbot.org/zone/import-confusion.htm

In general, using 'from blah import *' is frowned upon except in very specific cases. While it is easier up front, it makes the code hard to read later on, since you aren't explicitly dating where the functions or classes you are using are coming from.

In general, you'll want to be as specific as possible when importing things to keep your code clean and easy to read, even if it does make it a bit longer.

For example:

from CatAppA import *
from CatAppB import *

my_cat = get_cat('Katy Purry')

If we were inspecting this code, we wouldn't know whether or not get_cat() comes from CatApp A or B, which makes troubleshooting more difficult, especially if both apps (or modules) define a get_cat() function. It would be much better to say:

from CatAppA import get_cat
from CatAppB import say_meow

my_cat = get_cat('Katy Purry')

Now we know that get_cat() comes from CatAppA.

The other aspect to consider is memory use. If a module defines 500 functions, doing 'import modulename' will load all 500 in memory, rather than just picking out the one or two you might use.

Aside from that, all of your references would be prefixed with 'modulename', which may or may not make the code more readable.

In general, I import everything explicitly, and I use relative import paths for imports in files that are in the same directory:

from .models import Cat

Yes, it makes my import lines much longer, but having them more explicit makes the code much easier to read on larger chunks of code.

There it's some contention as to whether or not to use relative imports, some devs prefer to use the more explicit appname.models version. Both do the same thing.

Check out the Django source code to see how they handle imports, and definitely look at PEP8:

https://www.python.org/dev/peps/pep-0008/#imports

-James

jorr...@gmail.com

unread,
Jun 20, 2015, 1:53:42 PM6/20/15
to django...@googlegroups.com
Thank you for the very detailed explanations everyone!

Carl Meyer

unread,
Jun 21, 2015, 9:47:53 PM6/21/15
to django...@googlegroups.com
Hi,

On 06/19/2015 08:32 PM, Peith Vergil wrote:
> It depends on how your project files are structured. If you have a file
> structure that looks like this:
>
> app/
> __init__.py
> models.py
> views.py
> urls.py
>
> Then, you can simply use relative imports.
>
> In views.py:
> from models import *
>
> In urls.py:
> from views import *

This style of import is called "implicit relative imports", and you
should never use it. It is deprecated in Python 2, and doesn't work at
all in Python 3. (You can opt in to the Python 3 behavior in Python 2
with "from __future__ import absolute_import".)

The reason it is "implicit" is because it is ambiguous - the "models"
and "views" modules you are importing from could be relative to the
current module location, or "absolute" (directly on sys.path), and it
opens the possibility of accidentally shadowing a top-level installed
module (even a stdlib module) with a local module (e.g. if you put a
`datetime.py` or a `django.py` into your package), causing hard-to-debug
issues.

(Also, as has been mentioned, you shouldn't use `import *` because it
leads to ambiguity as to the source of names in your code.)

The right way to do relative imports is with the explicit syntax:

from .models import MyModel
from .views import some_view

or to import a whole module:

from . import models
from . import views

Using the `.` make it explicit that you are importing from a local
module relative to your current module, not from a top-level module.

Carl

> If, for example, your models live in a separate Django app (i.e. a
> separate Python package):
>
> app1/
> __init__.py
> views.py
> urls.py
> app2/
> __init__.py
> models.py
>
> Then, you have to import your models using its full path so Python will
> know where to look for it.
>
> In app1/views.py:
> from app2.models import *
>
> You should familiarize yourself on how Python imports work since this is
> more of a Python issue rather than a Django issue.
>
> On Jun 20, 2015 09:10, <jorr...@gmail.com
> <mailto:jorr...@gmail.com>> wrote:
>
> This is mostly a cosmetic question, and I could be completely wrong
> because I'm fairly new to Django, or it could be that there is a
> perfectly logical explanation for this, but here goes:
>
> It seems the code required to import views in urls.py and models in
> views.py is inconsistent (and in the case of urls.py perhaps redudant).
>
> To import views in urls.py I have to use
>
> |
> from<appname>importviews
> |
>
> ...while in views.py I can simply write
>
> |
> frommodels import*
> |
>
> Why do I need to reference the appname in urls.py but not in
> views.py? Or is there a reason for this?
>
> --
> You received this message because you are subscribed to the Google
> Groups "Django users" group.
> To unsubscribe from this group and stop receiving emails from it,
> send an email to django-users...@googlegroups.com
> <mailto:django-users...@googlegroups.com>.
> To post to this group, send email to django...@googlegroups.com
> <mailto:django...@googlegroups.com>.
> <https://groups.google.com/d/msgid/django-users/03eb4740-6503-4757-ae09-9183ac2b8502%40googlegroups.com?utm_medium=email&utm_source=footer>.
> For more options, visit https://groups.google.com/d/optout.
>
> --
> You received this message because you are subscribed to the Google
> Groups "Django users" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to django-users...@googlegroups.com
> <mailto:django-users...@googlegroups.com>.
> To post to this group, send email to django...@googlegroups.com
> <mailto:django...@googlegroups.com>.
> Visit this group at http://groups.google.com/group/django-users.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/django-users/CAMHY-KdkaS0RBdS4F4mi%3DaGHTP9uZThJVCesXM9%3DGbVbZoteaw%40mail.gmail.com
> <https://groups.google.com/d/msgid/django-users/CAMHY-KdkaS0RBdS4F4mi%3DaGHTP9uZThJVCesXM9%3DGbVbZoteaw%40mail.gmail.com?utm_medium=email&utm_source=footer>.
signature.asc

Carl Meyer

unread,
Jun 21, 2015, 9:58:03 PM6/21/15
to django...@googlegroups.com


On 06/19/2015 11:41 PM, James Schneider wrote:
> This is strictly a Python question, nothing Django-specific, but I've
> found this site to be helpful in explaining the different ways to import
> things:
>
> http://effbot.org/zone/import-confusion.htm

This is good as far as it goes, but it is also quite old, and thus
doesn't cover explicit relative imports at all (because they didn't
exist yet when it was written).

> In general, using 'from blah import *' is frowned upon except in very
> specific cases. While it is easier up front, it makes the code hard to
> read later on, since you aren't explicitly dating where the functions or
> classes you are using are coming from.
>
> In general, you'll want to be as specific as possible when importing
> things to keep your code clean and easy to read, even if it does make it
> a bit longer.
>
> For example:
>
> from CatAppA import *
> from CatAppB import *
>
> my_cat = get_cat('Katy Purry')
>
> If we were inspecting this code, we wouldn't know whether or not
> get_cat() comes from CatApp A or B, which makes troubleshooting more
> difficult, especially if both apps (or modules) define a get_cat()
> function. It would be much better to say:
>
> from CatAppA import get_cat
> from CatAppB import say_meow
>
> my_cat = get_cat('Katy Purry')
>
> Now we know that get_cat() comes from CatAppA.

Yes, that's a great description of the reason to avoid `import *`.

> The other aspect to consider is memory use. If a module defines 500
> functions, doing 'import modulename' will load all 500 in memory, rather
> than just picking out the one or two you might use.

This isn't true. When you first import a module (no matter what syntax
you use), its full code is executed, resulting in a module object with
all of its top-level objects and attributes defined, which is placed
into the `sys.modules` dictionary. So every function or class defined in
the module will be in memory no matter what.

The import syntax you use determines only which functions/objects you
get references to in the current module, it doesn't change memory usage
at all.

(Not to mention that, apart from extreme cases, memory usage of your
code objects themselves will be negligible compared to your data.)

> Aside from that, all of your references would be prefixed with
> 'modulename', which may or may not make the code more readable.

This isn't related to `import *`, it depends on the distinction between

from somemodule import some_func

vs

import somemodule

In the latter case, you would use `somemodule.some_func` in your code;
in the former you'd use `some_func`. Both of those are equally explicit;
the choice between them is really a matter of preference, conciseness,
and avoiding naming clashes. If I am using only one or two things from a
module (especially if I am using them many times), I'll usually use
`import from` to make the references shorter. If I am using many things
from the module, I'll prefer the latter form (and sometimes shorten the
module name with an alias, via `import somemodule as sm`).

> In general, I import everything explicitly, and I use relative import
> paths for imports in files that are in the same directory:
>
> from .models import Cat
>
> Yes, it makes my import lines much longer, but having them more explicit
> makes the code much easier to read on larger chunks of code.
>
> There it's some contention as to whether or not to use relative imports,
> some devs prefer to use the more explicit appname.models version. Both
> do the same thing.
>
> Check out the Django source code to see how they handle imports, and
> definitely look at PEP8:
>
> https://www.python.org/dev/peps/pep-0008/#imports

Good advice; PEP 8 gives useful guidance on these questions.

Carl

signature.asc

James Schneider

unread,
Jun 22, 2015, 1:20:56 AM6/22/15
to django...@googlegroups.com
>> If we were inspecting this code, we wouldn't know whether or not
>> get_cat() comes from CatApp A or B, which makes troubleshooting more
>> difficult, especially if both apps (or modules) define a get_cat()
>> function. It would be much better to say:
>>
>> from CatAppA import get_cat
>> from CatAppB import say_meow
>>
>> my_cat = get_cat('Katy Purry')
>>
>> Now we know that get_cat() comes from CatAppA.
>
> Yes, that's a great description of the reason to avoid `import *`.
>

Hey, thanks. :-D


>> The other aspect to consider is memory use. If a module defines 500
>> functions, doing 'import modulename' will load all 500 in memory, rather
>> than just picking out the one or two you might use.
>
> This isn't true. When you first import a module (no matter what syntax
> you use), its full code is executed, resulting in a module object with
> all of its top-level objects and attributes defined, which is placed
> into the `sys.modules` dictionary. So every function or class defined in
> the module will be in memory no matter what.
>
> The import syntax you use determines only which functions/objects you
> get references to in the current module, it doesn't change memory usage
> at all.
>
> (Not to mention that, apart from extreme cases, memory usage of your
> code objects themselves will be negligible compared to your data.)
>

I'll admit when I'm wrong. This is one of those instances that proves
you can't believe everything you read on the Internet. I had read
something to this effect some years ago, but haven't invested a ton of
research energy.

I'll defer to Carl, who likely has immeasurably more experience in
this area than I do based on responses I've seen from him in other
threads.

>> Aside from that, all of your references would be prefixed with
>> 'modulename', which may or may not make the code more readable.
>
> This isn't related to `import *`, it depends on the distinction between
>
> from somemodule import some_func
>
> vs
>
> import somemodule
>
> In the latter case, you would use `somemodule.some_func` in your code;
> in the former you'd use `some_func`. Both of those are equally explicit;
> the choice between them is really a matter of preference, conciseness,
> and avoiding naming clashes. If I am using only one or two things from a
> module (especially if I am using them many times), I'll usually use
> `import from` to make the references shorter. If I am using many things
> from the module, I'll prefer the latter form (and sometimes shorten the
> module name with an alias, via `import somemodule as sm`).
>

This is the exact point that I was driving at, however in re-reading
what I had wrote, I can see that I wasn't clear. Thanks for the
clarification.


Thanks Carl, I always enjoy reading your responses (even the ones
where you are disproving me ;-D). Your insights are always on point
and well stated.

-James
Reply all
Reply to author
Forward
0 new messages