I have some Django middleware code that connects to a database. I want to turn the middleware into a reusable application ("app") so I can package it for distribution into many other projects, without needing to copy-and-paste.
I don't understand where a reusable application is supposed to configure itself. Since it's intended for redistribution I don't have the ability to write the central settings.py myself. Looking at the Django documentation I see there's settings.configure but it appears to replace the entire configuration, instead of letting me "splice" a new database into DATABASES.
What's the right way to give my reusable middleware app the ability to configure its own database connection? I don't want it to interfere with the databases of applications where I'll be installing it. Thanks.
You could follow the approach of Django debug toolbar. It includes an app config class, and overrides the settings in the ready method.
You can see the code here.
Database Connection.
Well first of all I am not quite sure it's a good idea for a middleware to connect to anything other than the default database for the project. If you really want that feature it would be best to ask the user to add it to the settings file directly because the database connection settings will vary wildly from install to install.
If your app wants to make raw queries just do
from django.db import connection
cursor = connection.cursor()
It would be better to use the ORM if you can.
App specific settings
One method is to create a file called app_settings.py in your reusable app. Then you can add code like the following into it.
from django.conf import settings
SOME_APP_SETTING = getattr(settings, 'SOME_APP_SETTING', SOME_DEFAULT)
This allows anyone installing your app to change some of the settings in the main settings.py file.
If you really wanted to get fancy, you could create a custom database settings section here and allow the user to override it in the settings.py file.
Related
I like the Django ORM. It's simple, easy to use, and reasonably powerful.
I'm currently developing some internal sites for the VFX company I work for, for which I've used Django. In the meantime, we are developing other python applications and libraries to be used in various contexts in production. There's a number of places in which our core library needs to be interacting with some databases, and using an ORM like Django would really help things. I'm aware of other options like SqlAlchemy or PeeWee, but I'd like to see if Django will work since I use it on the websites and I like its API better.
Using Django as an ORM in a library is tricky (as I explored in a previous question), because Django expects to be used as a website with "apps". In a library, I might want to define any number of data models, which would exist in appropriate places in the library but not inside any Django app (as we're not using any other parts of the framework). So far so good.
I can create a baseclass for my models anywhere in the library as follows:
from django.db import models
from django.apps import apps
import django.conf
django.conf_settings.configure(
DATABASES = ...
)
apps.populate((__name__,))
class LibModel(models.Model):
class Meta:
abstract = True
app_label = __name__
Then anywhere in the library I can create my own models with this baseclass. Since I'm not relying on the "app" for the database names, I need to state them explicitly.
class SpecificModel(LibModel):
# fields go here
class Meta(LibModel.Meta):
db_table = "specific_model_table_name"
This gets around my concern of having to simulate the structure of an "app". The name property in the base class supplies Django with all it needs, and then Django quits whining about not finding an app. The other model files can live wherever they want.
However, there is a glaring use case where this all falls apart. Say that my Django web application wants to use some functionality from the company core python library, which now uses the Django ORM for various things. Since I make a call to django.conf.settings.configure in the library, Django is going to scream about defining the settings more than once when it tries to run the main application.
So basically, a library using the Django ORM is incompatible with Django. Wonderful.
Is there any way around this? I mean, it's a lovely ORM - is it really this impossible to use in a standalone modular way? Is the Django architecture utterly singleton in nature, making this impossible?
*Not a duplicate
I'm trying to have a company python library that uses Django as an ORM. Some of the things that could depend on it might be Django websites themselves. How do I get around Django's singleton insistence on only setting the settings config once? Or is it possible? None of these answers address this!
You can check if django has already been configured.
from django.apps import apps
from django.conf import settings
if not apps.ready:
settings.configure()
django.setup()
When starting Django application - core python library can be configured as separate app an be loaded on startup.
Also, check this answer on dynamic app loading at runtime.
A simple answer is how to initialize Django in a standalone application and do it compatible with Django applications.
import os
import django
if not 'DJANGO_SETTINGS_MODULE' in os.environ:
os.environ['DJANGO_SETTINGS_MODULE'] = 'mysettings'
# # or without DJANGO_SETTINGS_MODULE directly
# from django.conf import settings
# settings.configure(DATABASES=... other...)
django.setup()
# this shouldn't be before DJANGO_SETTINGS_MODULE or settings.configure(...)
from myapp.models import MyModel
# this shouldn't be called before django.setup()
queryset = MyModel.objects.filter(...)
This is more compatible with Django then the answer by Oleg Russkin (where a risk of cyclic dependency at django.setup() is possible if the code is called inside inside a setup() initiated by another similar code or a normal Django project started by manage. It is similar to manage.py where django.setup() is also called internally by execute_from_command_line(sys.argv). The setup initializes all modules related to INSTALLED_APPS all urls modules and consequently all views etc. Many of them are lazy, but still. If any code called by setup() depends on this then neither the condition not apps.ready doesn't help. The setup() is not reentrant and the startup fails.)
Much more general answer
An important concept of Django is to support writing reusable parts of code ("applications" in Django terminology, that can be developed and tested independently. There can be also a tree of dependencies, but uncontrolled mutual dependencies should be avoided if possible) Reusable applications are expected that they can be easier combined to whole project ("project" in Django terminology is with all settings necessary to run it by Python.)
The only unavoidable and useful "singleton" in Django ORM are database connections django.db.connections and django.conf.settings especially INSTALLED_APPS. Only one connection should be used to the same database from the same process or thread.
Django is very configurable. An extreme example: It is possible to write a single file project where all code like settings, models, URL configs and views is defined in one file. That extreme that is probably useful only for some special tests or very short demos or as an exercise. It is even possible to define a project by one file with two "reusable" applications :-)
Django supports also "legacy databases" where the database structure is shared with existing non Django applications and models can be created by inspectdb command. Table names in such models are explicit and don't contain the app name. On the other hand the app name prefix is useful to prevent a possible conflict of the same table names from independent "applications". An important decision is if you can use it as a "legacy" database or a normal Django database.
You can decide between following two solutions or to combine them:
Use e.g. foo_models or bar.models and import all models from them e.g. to app.models and add only that "app" to INSTALLED_APPLICATIONS. This can be viable if it is only for one company and never otherwise and central name assigment is possible. (easiest but little naive)
Use some coarse separation of namespaces to several apps. You should probably use not more than one app with simple names without app name prefix.
Think ahead about migrations**. They will be probably very complicated and very soon impossible if you will create later more projects for the same database and different subsets of database tables without separating them to more apps and without app namespace.
There is really no "singleton" in Django ORM except of django.db.connections itself. If you use more databases you can direct some tables to a specific database by DATABASE_ROUTERS, even with two different models that use the same table name without a prefix.
Iam trying to create multiple projects into one existing django project.
The directory should be set up as follows
directory picture
Is it possible to use this direcory without using multiple databases and config files. Everything in a single django instance?
If so, how?
The problem is, i cant reach the moduls in my mainproject urls.py. They cant be found.
thanks :)
Why would you want to do this? If you need two different django projects, keep them as different django projects.
It is different if you want to use the same database and reuse some of your existing apps.
For the first, you can set that in your settings.py file of each project to point to a common database, you can even manage to share only some tables in a common database and keep the others as a separated database for each project (there are some limitations with that approach though). Check django multidb docs for more info.
For the second, you can create a folder containing your django apps (with their models definitions, views, admin and whatever you need) and import them in the settings.py. An example:
APPS_PATH = "/django/apps/folder/"
sys.path.insert(0, APPS_PATH)
INSTALLED_APPS = (
...
custom_app1,
custom_app2,
)
You may also want to check django sites.
Hope it helps.
When working with databases with Django, it automatically creates 12 default tables in the database.
I understand that I need dango_session for storing the session and probably django_site. But why do I need the others?
In PHP I used to store users in my own custom tables. Shouldn't I do that anymore?
The tables are created because you have django.contrib.auth, django.contrib.sessions, and so on in your INSTALLED_APPS setting. You shouldn't delete the tables if the apps are installed, as Django will expect them to exist.
None of the contrib apps are required to run Django. However, I highly recommend that you use the Django auth and sessions app instead of writing your own. For example, if you use the auth app, you don't need to worry about how to hash passwords, and there are lots of helpful views included to log users in, reset passwords and so on.
I am relatively new to Django and one thing that has been on my mind is changing the database that will be used when running the project.
By default, the DATABASES 'default' is used to run my test project. But in the future, I want to be able to define a 'production' DATABASES configuration and have it use that instead.
In a production environment, I won't be able to "manage.py runserver" so I can't really set the settings.
I read a little bit about "routing" the database to use another database, but is there an easier way so that I won't need to create a new router every time I have another database I want to use (e.g. I can have test database, production database, and development database)?
You can just use a different settings.py in your production environment.
Or - which is a bit cleaner - you might want to create a file settings_local.py next to settings.py where you define a couple of settings that are specific for the current machine (like DEBUG, DATABASES, MEDIA_ROOT etc.) and do a from settings_local import * at the beginning of your generic settings.py file. Of course settings.py must not overwrite these imported settings.
Why you need a test database? Django create test database automatically before running unittest. And, database routing is not fit your purpose, it's for routing you read/write requests to different database. If you want to use a development database, set up a new DATABASE config in, say local_settings.py, and at the last of your settings.py, type
try:
from local_settings import *
except ImportError:
pass
There is nothing you can specify in the settings directly. The practice I use is to have addtional setting files for different environments which contain just the settings overwritten which I want to change, like database settings or cache settings for example. My project root application for example would contain the following files on a development environment (attention to the leading underscore):
...
settings.py
settings_dev.py
_settings_test.py
_settings_prod.py
...
Then in settings.py I would add the following lines of code to the beginning:
try:
from settings_prod import *
except ImportError:
try:
from settings_test import *
except ImportError:
from settings_dev import *
Since I am on dev environment it will only import my settings_dev file, since the others have a leading underscore.
When I deploy then to a production or testing environment I would rename the relevant files. For production: _settings_prod.py -> settings_prod.py, for testing: _settings_test.py -> settings_test.py. settings_dev.py can basically stay as is, since it will be only imported if the other two fail.
The last step you could simply do with automated deployment via fabric or other tools. An example with fabric would be something like run('mv _settings_prod.py settings_prod.py') for renaming.
I want to use Pinax for a small project , but I am confused because I don't if can extend/change the behavior and functional of the provided applications .
Is there any documentation for extending the behavior of the bundled applications ?
example: in registration application ,I want to add custom fields but I am not able to find proper documentation on how to achieve it..( mainly for those which need db changes )
Thanks !
Yes, you can extend the behaviour of the built-in applications. If you are using the pinax basic setup with user accounts and profiles, you will have to add the extra fields you want in apps/profiles/models.py. For a list of field types, see here: https://docs.djangoproject.com/en/1.3/ref/models/fields/
This will create the necessary db fields for you when you run manage.py syncdb. If you have already sync'd the db, however, you will have to manually add the db columns. If you don't have any data you care about in that table, you can always just drop the table and it will recreate it. Django doesn't modify db tables once they are created, even if you change the model.
You will also have to modify the signup form to include these new fields and point your urls.py to the new signup form you created. Copy the form from the site-packages/pinax directory to your project. Don't modify them directly.
If you haven't already, you should check out the Django tutorial here: https://docs.djangoproject.com/en/1.3/intro/tutorial01/
This will give you a good idea of how Django apps are put together and how the different pieces interact, so you can do a better job customizing Pinax to your liking. Make sure you know what models.py, urls.py, views.py, and the templates are doing.