Using only the DB part of Django
The short answer is: no, you can't use the Django ORM separately from Django.
The long answer is: yes, you can if you are willing to load large parts of Django along with it. For example, the database connection that is used by Django is opened when a request to Django occurs. This happens when a signal is sent so you could ostensibly send this signal to open the connection without using the specific request mechanism. Also, you'd need to setup the various applications and settings for the Django project.
Ultimately, it probably isn't worth your time. SQL Alchemy is a relatively well known Python ORM, which is actually more powerful than Django's anyway since it supports multiple database connections and connection pooling and other good stuff.
Edit: in response to James' criticism elsewhere, I will clarify what I described in my original post. While it is gratifying that a major Django contributor has called me out, I still think I'm right :)
First off, consider what needs to be done to use Django's ORM separate from any other part. You use one of the methods described by James for doing a basic setup of Django. But a number of these methods don't allow for using the syncdb
command, which is required to create the tables for your models. A settings.py file is needed for this, with variables not just for DATABASE_*
, but also INSTALLED_APPLICATIONS
with the correct paths to all models.py files.
It is possible to roll your own solution to use syncdb
without a settings.py, but it requires some advanced knowledge of Django. Of course, you don't need to use syncdb
; the tables can be created independently of the models. But it is an aspect of the ORM that is not available unless you put some effort into setup.
Secondly, consider how you would create your queries to the DB with the standard Model.objects.filter()
call. If this is done as part of a view, it's very simple: construct the QuerySet
and view the instances. For example:
tag_query = Tag.objects.filter( name='stackoverflow' )
if( tag_query.count() > 0 ):
tag = tag_query[0]
tag.name = 'stackoverflowed'
tag.save()
Nice, simple and clean. Now, without the crutch of Django's request/response chaining system, you need to initialise the database connection, make the query, then close the connection. So the above example becomes:from django.db import reset_queries, close_connection, _rollback_on_exception
reset_queries()
try:
tag_query = Tag.objects.filter( name='stackoverflow' )
if( tag_query.count() > 0 ):
tag = tag_query[0]
tag.name = 'stackoverflowed'
tag.save()
except:
_rollback_on_exception()
finally:
close_connection()
The database connection management can also be done via Django signals. All of the above is defined in django/db/init.py. Other ORMs also have this sort of connection management, but you don't need to dig into their source to find out how to do it. SQL Alchemy's connection management system is documented in the tutorials and elsewhere.Finally, you need to keep in mind that the database connection object is local to the current thread at all times, which may or may not limit you depending on your requirements. If your application is not stateless, like Django, but persistent, you may hit threading issues.
In conclusion, it is a matter of opinion. In my opinion, both the limitations of, and the setup required for, Django's ORM separate from the framework is too much of a liability. There are perfectly viable dedicated ORM solutions available elsewhere that are designed for library usage. Django's is not.
Don't think that all of the above shows I dislike Django and all it's workings, I really do like Django a lot! But I'm realistic about what it's capabilities are and being an ORM library is not one of them.
P.S. Multiple database connection support is being worked on. But it's not there now.
Use only some parts of Django?
I myself use Django for its object/db mapping without using its urlconfigs. Simply create a file called djangosettings.py
and insert the necessary configuration, for example:
DATABASE_ENGINE = 'oracle'
DATABASE_HOST = 'localhost'
DATABASE_NAME = 'ORCL'
DATABASE_USER = 'scott'
DATABASE_PASSWORD = 'tiger'
Then in your regular Python code, doimport os
os.environ["DJANGO_SETTINGS_MODULE"] = "djangosettings"
before you import any Django modules. This will let you use Django's object/db mappings without actually having a Django project, so you can use it for standalone scripts or other web applications or whatever you want.As for caching, if you don't want to use Django then you should probably decide what you are using and go from there. I recommend using CherryPy, which doesn't use Django-style regular expression URL mapping, but instead automatically maps URLs to functions based on the function names. There's an example right at the top of the CherryPy home page: http://cherrypy.org/
CherryPy has its own caching system, so you can accomplish exactly the same thing as what Django does but without needing to use Django's urlconfig system.
Django - how to specify a database for a model?
As far as I know you can't specify the database directly with the model since it would kind of prevent the app from ever being reusable, but from what I can see in the docs:
https://docs.djangoproject.com/en/1.8/topics/db/multi-db/
Use multiple databases in Django with only one table django_migrations
Thanks to the comments on my question I did some research and came up with the following findings.
Using multiple databases results in creating a table django_migrations
when migrations are used. There is no option to record the migrations in only one table django_migrations
, as the comment from Kamil Niski explains. This is clear after reading the file django/db/migrations/recorder.py
.
I will illustrate an example with a project foo
and an app bar
inside the project. The app bar
has only one model Baz
.
We create the project:
django-admin startproject foo
Now we have these contents inside the main project directory:- foo
- manage.py
I have a habit to group all apps inside the project directory:mkdir foo/bar
python manage.py bar foo/bar
In the file foo/settings.py
we adjust the settings to use two different databases, for the purposes of this example we use sqlite3
:DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db1.sqlite3'),
},
'remote': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db2.sqlite3'),
}
}
Now we run the migrations:python manage.py migrate --database=default
This runs all migrations, the part --database=default
is optional, because if not specified Django uses the default database.Django has applied all migrations to the default database:
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying sessions.0001_initial... OK
Now we create the model
1 contenttypes 0001_initial 2019-11-13 16:51:04.767382
2 auth 0001_initial 2019-11-13 16:51:04.792245
3 admin 0001_initial 2019-11-13 16:51:04.827454
4 admin 0002_logentr 2019-11-13 16:51:04.846627
5 admin 0003_logentr 2019-11-13 16:51:04.864458
6 contenttypes 0002_remove_ 2019-11-13 16:51:04.892220
7 auth 0002_alter_p 2019-11-13 16:51:04.906449
8 auth 0003_alter_u 2019-11-13 16:51:04.923902
9 auth 0004_alter_u 2019-11-13 16:51:04.941707
10 auth 0005_alter_u 2019-11-13 16:51:04.958371
11 auth 0006_require 2019-11-13 16:51:04.965527
12 auth 0007_alter_v 2019-11-13 16:51:04.981532
13 auth 0008_alter_u 2019-11-13 16:51:05.004149
14 auth 0009_alter_u 2019-11-13 16:51:05.019705
15 auth 0010_alter_g 2019-11-13 16:51:05.037023
16 auth 0011_update_ 2019-11-13 16:51:05.054449
17 sessions 0001_initial 2019-11-13 16:51:05.063868
Baz
:models.py
:
from django.db import models
class Baz(models.Model):
name = models.CharField(max_length=255, unique=True)
register the app bar
into INSTALLED_APPS
(foo/settings.py
) and create the migrations:python manage.py makemigrations bar
Before we run the migrations we create routers.py
inside the bar
app:class BarRouter(object):and register it in
def db_for_read(self, model, **hints):
if model._meta.app_label == 'bar':
return 'remote'
return None
def db_for_write(self, model, **hints):
if model._meta.app_label == 'bar':
return 'remote'
return None
def allow_relation(self, obj1, obj2, **hints):
return None
def allow_migrate(self, db, app_label, model_name=None, **hints):
if app_label == 'bar':
return db == 'remote'
if db == 'remote':
return False
return None
foo/settings.py
:DATABASE_ROUTERS = ['foo.bar.routers.BarRouter']
Now the naive approach would be to run the migrations for bar
into the remote
database:python manage.py migrate bar --database=remote
Operations to perform:The migrations has been applied to the
Apply all migrations: bar
Running migrations:
Applying bar.0001_initial... OK
remote
database:1 bar 0001_initial 2019-11-13 17:32:39.701784When we run:
python manage.py runserver
the following warning will be raised:Everything seems to work fine though. However it isn't satisfying having this warning.You have 1 unapplied migration(s). Your project may not work properly
until you apply the migrations for app(s): bar.
Run 'python manage.py migrate' to apply them.
The proper way would be to run all migrations for each database as suggested in this answer.
It would look like this:
python manage.py migrate --database=default
python manage.py migrate --database=remote
and after creating the migrations for bar
:python manage.py migrate bar --database=default
python manage.py migrate bar --database=remote
The router will take care that the table bar_baz
is created only in the remote
database, but Django will mark the migrations as applied in both databases. Also the tables for auth
, admin
, sessions
, etc. will be created only in the default
database, as specified in routers.py
. The table django_migrations
in the remote
database will have records for these migrations too.It is a long reading, but I hope it sheds some light on this, in my opinion, not thoroughly explained issue in the official documentation.
Django database API (model layer) without installing django?
It's not currently possible to just install Django's ORM without the rest of it. You can install the whole lot and just use the ORM, though.
Alternatively you might like to look into one of the standalone Python db wrappers/ORMs. The big one is SQLAlchemy, and there's also the smaller SQLObject.
How to only update part of db record parameters with django rest framework when do http put?
You need to use PATCH
method for partial update:
curl -X PATCH -H 'Content-Type: application/json' -i 'http://127.0.0.1:8000/info/my_key_1/' --data '{"para1": "hi"}'
Related Topics
Is There a Builtin Identity Function in Python
Hide Chromedriver Console in Python
What's the Best Way to Store a Phone Number in Django Models
Unexpected Results Converting Timezones in Python
Pandas: Subindexing Dataframes: Copies VS Views
How to Use Numpy.Correlate to Do Autocorrelation
Scale Everything on Pygame Display Surface
Does Python Do Slice-By-Reference on Strings
How to Access Class Member Variables in Python
Python 'Requests' Library - Define Specific Dns
Typeerror: Expected a Character Buffer Object - While Trying to Save Integer to Textfile
Numpy Array Dtype Is Coming as Int32 by Default in a Windows 10 64 Bit MAChine
Time Complexity of String Concatenation in Python