Django application override & import path? - python

Let's have a django project using a 3rd party application.
I'd like to override some of its modules without touching original files.
Simple subclassing is not possible here, need to override code transparently as many other apps rely on original class names and functions.
Project's structure looks like:
django_project/
__init__.py
settings.py
overrides/ <-- here is a subdir with apps overrides
__init__.py
payment/ <-- here is an example of app to override
__init__.py
admin.py
forms.py <-- this file is ignored, original is imported
models.py
tests.py
views.py
settings.py was modified with
INSTALLED_APPS=(
'satchmo_store.shop'
#'payment' # original values
'overrides.payment' # modified app
...
)
The above solution however does not work, because Django does not insert path of added app into modules search path (sys.path).
Django just loads admin.py, models.py, tests.py and views.py, other files like forms.py are ignored.
Is this behaviour documented somewhere ? What exactly placing a module name in INSTALLED_APPS does behind scenes ?
I hacked the situation with hardcoding new modules search path in manage.py and Apache's setting of WSGIPythonPath.
import os.path
import sys
DIRNAME = os.path.dirname(__file__)
APPS_OVERRIDE = os.path.join(DIRNAME, 'overrides')
if not APPS_OVERRIDE in sys.path:
sys.path.insert(1, APPS_OVERRIDE)
I doubt this is the right way. Cann't find a guide describing apps overriding.
So, how can I properly override external Django application in my project ?
The bonus question: Do I need to copy whole application directory tree, not just particular files which are really modified ? As far as I know, Python stops at first matching module path, so it won't import other modules available in following parts of the search path.

Example of how to override your form:
overrides/payment/forms.py
from django import forms
class YourNewFormThingy(forms.Form): pass
overrides/payment/models.py
from satchmo.payment import forms as satchmo_payment_forms
from . import forms
satchmo_payment_forms.SomeForm = forms.YourNewFormThingy

Try including payment as well along with override.payment as satchmo uses payment module to process payments and payment code is flexible enough to include your code as well.

Related

How to use Django model in an external python script within the project?

I want to use a Django model in an external python script. This python script is placed within the root directory of my project and I also created an init.py module for easy importing. Can anyone please instruct on what is the most secure and efficient way of importing a Django model into the python script?
I would also appreciate it if someone could advise me whether or not it is accurate to place an init.py module within the root directory. If not, what is the best way of doing this?
use this solution only if you want your scripts to be standalone (you want to access models when server is not running)
There are basically two different ways to do that:
If you are going to run this code frequently, I strongly suggest that you create a management command for the code. (check instructions here)
But if it's a bulk-data-import or something that's not gonna run many times, you can use something like this (put this in the root of your django app - beside manage.py):
import os
import django
if __name__ == '__main__':
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "<your_project_name>.settings")
django.setup()
# now you have access to your models
# as an example:
# from users.models import User
#
# for user in User.objects.all():
# print(user)
also keep in mind that you should always import your models after django.setup(), otherwise, you'll get an error.
I would also appreciate it if someone could advise me whether or not it is accurate to place an init.py module within the root directory. If not, what is the best way of doing this?
If you want to have multiple script files, it's not a good idea to put them in the root of django project. You can create a python package, say my_scripts, beside manage.py and put your scripts there.
So you will end up with something like this:
...
manage.py
my_scripts
├── __init__.py
└── first_script.py
But now you need to make a little change in the script file to make it work correctly. You should append the BASE_DIR to your path so that python can recognize the settings file (or module, if you extend it):
import os
import sys
import django
if __name__ == '__main__':
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "<your_project_name>.settings")
django.setup()
# now you have access to your models
# as an example:
# from users.models import User
#
# for user in User.objects.all():
# print(user)

Reroute import pathes in django

I want to use a django app (newapp) in my django project. To keep it simply updated, I would like to include it as git submodule, but this will lead to a folder structure like:
myproject
|-app
|-newapp-git
|-newapp
|-settings.py
|-urls.py
|-...
|-README.md
That is because, newapp is unfortuntely not only the appfolder but also some files (like readme) and the subfolder newapp. I can add this in INSTALLED_APPS with newapp-git.newapp, but the app itself imports models etc. with import newapp which does not work, and I cannot change it because I dont want to modify the content in newapp to keep it updated simply.
So, is there a chance to tell django, that imports from newapp should be rerouted to newapp-git.newapp?

How to "autodiscover" a different location for the admin.py file?

I think it makes sense to organize my Django apps in a different way (by protocol):
📂myapp
apps.py
models.py
utilities.py
📂html
admin.py
urls.py
views.py
📂rest
serializers.py
urls.py
views.py
📂graphql
etc
This would move the admin.py file into the html folder, but sadly autodiscover does not seem to find it anywhere else than in the myapp folder. Is there a way to point to the correct location: perhaps in apps.py? I am sure a symlink would work, but not really what I am after.
There's nothing magic about either admin.py or autodiscover. All admin.py does is run any register calls on import, and all autodiscover does is look for an admin.py file in each installed app and import it. There's nothing to stop you importing your admin.py in its custom location from somewhere else, eg the models or views files.
This was somewhat tricky, but the comment by #Joran Beasley set me in the right direction.
For admin.py to be autodiscovered it needs to be either in the top level app folder, or be imported in a file. However... not every file works.
If you do from .html import admin
into __init__.py or apps.py: django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.
into models.py: Results in an importerror from models into admin. I think due to the circular nature of the imports.
However the following works: from . import admin inside the urls.py. Make sure to add a comment that this import is needed for autodiscover purposes.

How would you go about creating a "config" class in Django?

I'm making a very very reusable CMS in Django. I'm trying not to hardcode anything, so I want a config.py or something for the app itself.
I want to use it in templates (something like {{ config.SITE_NAME }}) and just regular Python code (views, models), etc.
How would I go about doing that?
Django already has the settings.py file and an interface to use the values from there, is that not good enough? Accessing settings in your code is easy:
from django.conf import settings
do_something_with(settings.MY_CONFIG_VARIABLE)
In your template it requires a bit more work, like making a context processor for example. This answer shows you have to make a context processor that exposes values from settings to your template.
settings.py serves this purpose already in django. You can add custom settings to it for your application.
https://docs.djangoproject.com/en/dev/topics/settings/#using-settings-in-python-code
When you create a django project, it automatically creates a settings.py file. Put your settings in that file, and then :-
from django.conf import settings
settings.YOUR_SETTING
also, if you have some settings, that will vary depending upon the machines (eg. production/test servers).
Then just add eg. conf/local_settings.py file and put the machine specific settings in that file, and in settings.py just do :-
from conf.local_settings import *
at the end of settings.py
Make sure you ignore local_settings.py from your VCS check-in (eg. in case of git add local_settings.py to .gitignore

How to resolve these Python errors in Django?

I'm trying to make my way through the Django Project's tutorial.
I've made it as far as this: https://docs.djangoproject.com/en/1.3/intro/tutorial02/#s-make-the-poll-app-modifiable-in-the-admin but I'm seeing errors in some of the files, e.g. in the admin.py file:
from polls.models import Poll
from django.contrib import admin
admin.site.register(Poll)
I'm getting the error
Unresolved import: Poll
The models are defined as outlined in the tutorial:
import datetime
from django.db import models
class Poll(models.Model):
question = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
def __unicode__(self):
return self.question
def was_published_today(self):
return self.pub_date.date() == datetime.date.today()
class Choice(models.Model):
poll = models.ForeignKey(Poll)
choice = models.CharField(max_length=200)
votes = models.IntegerField()
def __unicode__(self):
return self.choice
The tutorial states that when I restart the server after adding the admin file, I should see the Poll app referenced in the Admin page at 127.0.0.1:8000, but all I'm seeing is this:
I'm also seeing
Unresolved import: Poll admin.py /newProj/src/newProj/polls line 0 PyDev Problem
Unresolved import: settings manage.py /firstproject/firstproject line 10 PyDev Problem
Unresolved import: settings manage.py /newProj/src/newProj line 10 PyDev
Are the errors the reason why I wouldn't be seeing the Site administration page updated with the Polls app?
How can I resolve these errors?
/newProj/src/newProj/polls and /firstproject/firstproject... eeek, this looks to be honest like the source of a few problems. OK, a few concepts:
Python packages: All python applications can be comprised of packages. These are basically just directories containing a __init__.py file.
How python finds packages: Well, python can do one of two things when it looks for packages:
If the current directory is a package, i.e. contains __init__.py, it can import from files in it.
It can search on the python path (PYTHONPATH environment variable, or sys.path - same thing) and then down into sub packages.
How django projects are laid out: A default django project looks something like this:
project_folder/
__init__.py
settings.py # config
urls.py # url config
polls/
__init__.py # makes polls a package
models.py # models
admin.py # admin
views.py # app views
forms.py # per app forms
urls.py # per app urls
In this layout, there are two possibilities for your admin.py when you runserver:
from models import Poll - this works because you're remaining within the scope of your package.
from polls.models import Poll - works because polls is a package and so is the parent from where you're running runserver.
Although it's tempting, don't use project_folder as a package. It'll break the code as soon as you rename the dir (for example, during deployment).
So, with all that in mind:
verify your __init__.py files exist in the right places and that you're using a directory structure kinda like the one above. Might be best to check outside the IDE too - IDEs can be... difficult.
verify your path is searching where you think it is. The current directory should work just fine; if it isn't, you can see
import sys
print sys.path
will allow you to view where you're looking. You can explicitly add the current directory, but you shouldn't need to.
I don't like PyDev. Totally personal preference here, but I find it hard work, over and above the usual editor of choice + terminal + file browser. You might too, especially if you find the directory structure is radically different in your file browser as compared to what you think you have with the IDE.
You are using Pydev, which add an additional layer of abstraction on the importing process.
Use a light text editor and a console for learning. You can switch to an IDE once the Python Path and the import logic are clear enough in your head so you can setup Pydev yourself.
Are the errors the reason why I wouldn't be seeing the Site
administration page updated with the Polls app?
The answer to this question is in the same page, at https://docs.djangoproject.com/en/1.3/intro/tutorial02/#customize-the-admin-form
try this:
import newProj.poll.models

Categories