paths not being consistent python django - python

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.

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

Ensure that a path to a dir is a Django project

For the last two days I am struggling with the following question:
Given an absolute path (string) to a directory (inside my file system or the server, it doesn't matter), determine if this dir contains a valid Django project.
First, I thought of looking for the manage.py underneath, but what if some user omit or rename this file?
Secondly, I thought of locating the settings module but I want the project root, what if the settings is 2 or more levels deep?
Third, I thought of locating the (standard) BASE_DIR name inside settings, but what if the user has not defined it or renamed it?
Is there a way to properly identify a directory as a valid Django project? Am I missing something?
One way you can try is searching/reading the.py files in the directory and match with regex a pattern describing
the distinctive django main function and package names.
Might be lucrative, but... eh
As bruno desthuilliers mentioned in the comments, there is no fail-safe solution.
But it depends on what do you need it for. I mean, how strict it has to be (or how good?). I have seen a few times the usage of PROJECT_DIR instead of BASE_DIR. And about the settings, I've seen single settings.py file and several settings files within a settings directory.
The main challenge would be Django not having that much hard naming rules for files/modules. You can pretty much name your files whatever, as far as you put the pieces together properly.
If I'm not mistaken, the only hard rule Django has is the models.py file. A Django app must have a file named models.py. But, your Django application doesn't necessarily need to have any app installed.
If you only need a good enough solution, I would say manage.py is a good candidate. You could double check and open the file and see if there's a django import there. If no manage.py, check if there's a requirements.txt and check if Django is listed there. If no requirements.txt, check for a directory named requirements and for text files within.
Something you could do to find some patterns is browsing the repositories tagged as with "django" tag on GitHub. Maybe use their API and clone all repositories (it will only list the top 2000 repos) to your local machine or to a server. Clone some rails, javascript, etc. repos as well and write your code step by step. Just search for a manage.py, if the result is satisfatory, that's it. If not, add a couple of more rules and test against the cloned repositories until you find a good enough solution for your problem.

How to override an app in Django properly?

I'm running Satchmo. There are many apps and I've changed some of the source in the Product app.
So my question is how can I override this properly because the change is site specific. Do I have to copy over the whole Satchmo framework and put it into my project or can I just copy one of the apps out and place it in say Satchmo>App>Products? (Kinda like with templates)
Thanks
What I have done which works is to copy the application that I have changed. In this case satchmo\apps\product.
I copied the app into my project folder
Amended my setting.py INSTALLED_APPS from 'product', to 'myproject.product',
This now carries the changes I've made to this app for this project only and leaves the original product app untouched and still able to be read normally from other projects.
When you add a 'Django App' to INSTALLED_APPS in your settings.py file, you're telling Django that there exists an importable python module with that name on your "python path". You can view your python path by viewing the contents of the list stored at sys.path.
Whenever Python (and in this case Django) attempts to import a module it checks each of the directories listed in sys.path in order, when it finds a module matching the given name it stops.
The solution to your problem then is too place your customized Django Apps, e.g., the Satchmo product module, into a location in your python path which will be checked before the "real" Satchmo product module.
Because I don't know how you have your directory structure laid out I'm basically making a guess here, but in your case, it sounds like you have the Satchmo apps living somewhere like /satchmo/apps/ and your project at /my_custom_path/my_project/. In which case you might want to add your customized product module to /my_custom_path/my_project/product/. Because the path at which your Django settings.py file lives is always checked first, that should mean that your customized product module will be found first and imported instead of the built in Satchmo one.
FYI: To check and see the order in which your Satchmo installation is checking directories for modules run python manage.py shell and then in the prompt do import sys; print sys.path.
Normally, I'd say the best thing is to fork Satchmo and keep a copy with your changes.
If you are willing to play with the python path, make sure that your app's directory appears before the other (default) directory. From my tests, if you have two apps/modules with identical names, the first one found is used.

Django, Python Modules, and Git Submodules

I am working on a django project that has uses multiple applications (python modules). Most of those python modules are maintained by other people in their own git repositories. I use the git-submodules command to import them into my project under the 'apps' directory like so:
mysite/
mysite/apps
mysite/apps/django-extensions
mysite/apps/django-celery
mysite/apps/django-comments
mysite/apps/myapp
...etc
Most of those submodules (take django-extensions for example) have a subfolder containing the actual python module: mysite/apps/django-extensions/django_extensions
This means I can't simply set my python path to include mysite/apps--I have to set it to include mysite/apps/django-extensions so it can import the django_extensions subfolder.
It gets annoying typing:
PYTHONPATH=mysite/apps/django-extensions:mysite/apps/django-celery... python manage.py runserver
Is there an easier way I should be laying out my repo? An easier process?
Just for fun, I tried a PYTHONPATH of mysite/apps/*, but that didn't work.
This is the wrong way to do it. Don't install other people's third-party code in your own project file. Instead, create a virtualenv, and install the code directly using pip.
After coming up blank on the internet, I hacked this solution together. It's straight forward and works well enough:
#At the top of settings.py
import sys, os
git_sub_modules = '/path/to/dir/containing/submodules' #Relative paths ok too
for dir in os.listdir(git_sub_modules):
path = os.path.join(git_sub_modules, dir)
if not path in sys.path:
sys.path.append(path)
time passes
UPDATE: It's much easier to use a virtualenv and/or something like dokku for deploying apps. I no longer use this. Although it is still a pain to checkout 3rd party apps that need 'tweaks' and use them in the project.
You could tuck those paths in a dependencies.pth file, and only have the .pth in your path. There are examples in your site-packages / dist-packages.
Could you try checking out just the wanted part of the repository? So if they have the actual code inside of what you're checking out, don't check out the extra part.
So instead of getting django-extensions get django-extensions/django-extensions.
Edit: I believe this is what you could do above.
Also, I believe you could get away with adding an __init__.py in the first django-extensions directory, but then you're going to have to add an extra django-extensions to your imports as well (__init__.py tells python it is a package). While I think this might work, I would recommend shooting for my first example.

Why are django projects python packages?

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.

Categories

Resources