Why are django projects python packages? - python

Why aren't they simply directories? Any good advice says to keep as much as possible in the apps and not to couple them to the project. The very ability to import an app as project.application discourages this. Why does django-admin.py create the __init__.py at all? The project is perfectly useful without it. What is the justification?

We have a single project that we "subclass" of sorts for other projects. So we have other projects that import stuff from the main project. I guess for us it provides the common namespace that contains all the other apps.
We could move to a package with all our apps in it separate from the projects i guess. Our system has grown rather than been planned.
So I guess my answer is, it provides a good root namespace. (for our needs) :)

The core of a project is a settings.py and a root urls.py. Both of those are Python modules, thus they need to be importable somehow. You can put the project directory directly on the Python path and thus make them importable as top-level modules, but that's arguably even worse practice. Better to have the project be a package and the settings and urls be modules within it.

There isn't a requirement that apps be inside the project's namespace, to my knowledge. Just that they be on the $PYTHONPATH. As such, they are usable by any other code on the system which shares the same PYTHONPATH.

I think the idea is that you can reuse the applications but you don't need to move them from the project where they were initially created. If the project weren't a package you would need to copy/move the application you want to reuse to a python package. Because of that being the project itself a proper python package you can reuse the applications in it without moving the applications to other place.

Related

Django : Why should I add package name inside INSTALLED_APPS?

In Djano, why should I add third-party package names inside the INSTALLED_APPS for some packages such as django-filter, DRF, debug-toolbar etc, while I don't want to add for some packages such as Celery, Requests etc ?
I couldn't figure out why should add them to a specific list, even though they all are similar pip packages and I installed them in the same way. Thanks in advance!
From docs :
Package? App?
A Python package provides a way of grouping related Python code for
easy reuse. A package contains one or more files of Python code (also
known as “modules”).
A package can be imported with import foo.bar or from foo import bar.
For a directory (like polls) to form a package, it must contain a
special file init.py, even if this file is empty.
A Django application is just a Python package that is specifically
intended for use in a Django project. An application may use common
Django conventions, such as having models, tests, urls, and views
submodules.
From above statements we understand that every well-written python code could be a package, now if this package is a bunch of python code in a directory, installing it would mean just copy the directory in your project and import them wherever needed in code.
But now there is this package which was already a django app and maybe used some special advantages of being one. Like exposing a restful API or delivering some sort of static resources or even working with special django-specific classes. these kind's of operation's need your direct permission in settings.py so that your project will know how to deal with this package. or even they may require to include their url path's to your project so that people visiting your site could access them.
I assume all this manual job is an act of security.
You need to add apps with models(non-abstract), templates, templatetags or management commands so that django-admin finds and loads them

Any issues with using "<namespace>.django.<app-name>" for django applications?

I know Django applications are typically named django-appname, however, our non-django packages are released under a namespace for our company (eg. company.modulename). Our Django applications are currently structured in a "django" namespace within that namespace (eg. company.django.appname).
We are evaluating our structure before releasing Django apps. Regardless of the internal path structure, which do you think would be a better project name convention for Django apps and why?
"django-company-appname" <-- more like community naming
"company.django.appname" <-- matches the internal structure and non-django python packages we release.
Edit:
Let me make this a little more clear. We already are using namespaces--our django apps are imported using "company.django.appname". What we are trying to decide, is if the name we use to release that app, as defined in setup.py and listed in PyPI/Github will be "company.django.appname" like our other Python releases or if we should do "django-company-app" instead.
We use a company.modulename style namespace for a few django apps and have encountered no problems.
In the __init__.py files we declare the namespace.
import pkg_resources
pkg_resources.declare_namespace(__name__)
and it's worked fine so far.
Forcing absolute imports will remove any chance of issues due to reuse of package names.

django shared library/classes

Am new to django and was looking for advice where to place my shared library. Am planning on creating classes that I want to use across all my apps within the project. Where would be the best location to place them?
e.x abstract models
regards,
We usually set our projects up like this:
/site/
__init__.py
manage.py
settings.py
urls.py
/apps/
__init__.py
/appA/
__init__.py
/appB/
__init__.py
/lib/
__init__.py
/django-lib/
__init__.py
/shared-lib/
__init__.py
Just make sure your site directory is on your python path:
import sys
sys.path.append('/path/to/site/')
Also, ensure that an init.py exists in site, apps, and lib so they can be treated as modules using dot notation imports (import site.lib.shared-lib)
Edit:
In answer to your question regarding your python path, it all has to do with where your 'manage.py' or equivalent file resides. If it is under the /site/ directory (next to apps and lib) then the PYTHONPATH should be fine.
You need to make sure that every directory contains an empty file called __init__.py. This tells Python to treat that directory as a module. See the new and improved ASCII art above.
What I learned from Two Scoops of Django is that you put the shared code inside a Django app that you create on your own called core.
To use the core app then is similar to how you cross-use classes from other apps.
To learn more, go to Chapter 28 of the book titled: "What About Those Random Utilities?"
If the shared library is going to be used in others projects as well you can make a installer using distutils.
But if it's only for the apps in the project you can take AntonioP's answer.
Remember that the root of your project (folder that contains manage.py) is always in your PYTHON_PATH when you run your django project, so you can create a folder deps or dependencies or extra or anything you like it that contains your shared libraries.
Wherever you want, you can import them if they are in the PYTHON_PATH.

paths not being consistent python django

I'm trying to import sorl-thumbnail into my app in django. Now the way that I have the site set up, using mod_wsgi on CentOS 5 with cpanel, the path for the apps must have the project name when importing... which is a pain.
Obviously this is a cause of concern with portability of the app. I'm importing sorl-thumbnail, in previous apps I've just added sorl.thumbnail to the installed apps and it's worked.
However now it's causing issues unless I have the project name www. in front of the import path. It's never done this before and I can't seem to get around the path issue.
I've added www.sorl.thumbnail also but then the rest of the paths in the sorl files have errors. Any ideas on how to remedy this or fix a work around?
You shouldn't need to use the project name when importing - just make sure that the apps are somewhere on your python path. Something along the lines of:
sys.path.append('/etc/django/domains/mydomain.com/myproject/')
... in your .wsgi file should do it (with the path to your own project, of course).
Ideally reusable apps should be outside of your project directory anyway, so consider creating a folder such as '/etc/django/lib/' to contain reusable apps and appending that to sys.path in your wsgi handler too.
Or, if you don't like that, perhaps use virtualenv and add your reusable apps directly to site-packages.
Or, if you don't like that, put your reusable apps somewhere else and symlink them to site-packages or somewhere on your python path.
In short, just make sure the package/module you're importing is on your python path. If you find yourself adding the project name or 'www' to a bunch of import paths, then you're probably doing something wrong.

How to modularize a Python application

I've got a number of scripts that use common definitions. How do I split them in multiple files? Furthermore, the application can not be installed in any way in my scenario; it must be possible to have an arbitrary number of versions concurrently running and it must work without superuser rights. Solutions I've come up with are:
Duplicate code in every
script. Messy, and probably the worst
scheme.
Put all scripts and common
code in a single directory, and
use from . import to load them.
The downside of this approach is that
I'd like to put my libraries in other
directory than the applications.
Put common
code in its own directory, write a __init__.py that imports all submodules and finally use from . import to load them.
Keeps code organized, but it's a little bit of overhead to maintain __init__.py and qualify names.
Add the library directory to
sys.path and
import. I tend to
this, but I'm not sure whether
fiddling with sys.path
is nice code.
Load using
execfile
(exec in Python 3).
Combines the advantages of the
previous two approaches: Only one
line per module needed, and I can use
a dedicated. On the other hand, this
evades the python module concept and
polutes the global namespace.
Write and install a module using
distutils. This
installs the library for all python
scripts and needs superuser rights
and impacts other applications and is hence not applicable in my case.
What is the best method?
Adding to sys.path (usually using site.addsitedir) is quite common and not particularly frowned upon. Certainly you will want your common working shared stuff to be in modules somewhere convenient.
If you are using Python 2.6+ there's already a user-level modules folder you can use without having to add to sys.path or PYTHONPATH. It's ~/.local/lib/python2.6/site-packages on Unix-likes - see PEP 370 for more information.
You can set the PYTHONPATH environment variable to the directory where your library files are located. This adds that path to the library search path and you can use a normal import to import them.
If you have multiple environments which have various combinations of dependencies, a good solution is to use virtualenv to create sandboxed Python environments, each with their own set of installed packages. Each environment will function in the same way as a system-wide Python site-packages setup, but no superuser rights are required to create local environments.
Google has plenty of info, but this looks like a pretty good starting point.
Another alternative to manually adding the path to sys.path is to use the environment variable PYTHONPATH.
Also, distutils allows you to specify a custom installation directory using
python setup.py install --home=/my/dir
However, neither of these may be practical if you need to have multiple versions running simultaneously with the same module names. In that case you're probably best off modifying sys.path.
I've used the third approach (add the directories to sys.path) for more than one project, and I think it's a valid approach.

Categories

Resources