web-dev-qa-db-fra.com

Utiliser uniquement la partie DB de Django

Est-ce que quelqu'un sait à quel point Django est "modulaire"? Puis-je utiliser uniquement la partie ORM pour obtenir des classes mappées sur des tables de base de données et savoir lire/écrire à partir de ces tables?

Si non, que recommanderiez-vous comme "l'équivalent Python d'Hibernate"?

39
M. Elkstein

La réponse courte est: non, vous ne pouvez pas utiliser l'ORM de Django séparément de Django.

La réponse longue est: oui, vous le pouvez si vous souhaitez charger de grandes parties de Django avec. Par exemple, la connexion à la base de données utilisée par Django est ouverte lorsqu'une demande à Django est émise. Cela se produit lorsqu'un signal est envoyé afin que vous puissiez apparemment l'envoyer pour ouvrir la connexion sans utiliser le mécanisme de demande spécifique. En outre, vous devez configurer les différentes applications et paramètres du projet Django. 

En fin de compte, cela ne vaut probablement pas la peine. SQL Alchemy est un ORM Python relativement bien connu, qui est en réalité plus puissant que celui de Django, car il prend en charge plusieurs connexions de base de données et regroupement de connexions, entre autres.


Edit: En réponse aux critiques de James formulées ailleurs, je vais clarifier ce que j'ai décrit dans mon post original. Bien qu'il soit gratifiant qu'un contributeur majeur de Django m'ait appelé, je pense toujours que j'ai raison :)

Tout d'abord, réfléchissez à ce qui doit être fait pour utiliser l'ORM de Django séparément de toute autre partie. Vous utilisez l’une des méthodes décrites par James pour effectuer une configuration de base de Django. Toutefois, certaines de ces méthodes ne permettent pas d'utiliser la commande syncdb, indispensable pour créer les tables pour vos modèles. Un fichier settings.py est nécessaire à cet effet, avec des variables non seulement pour DATABASE_*, mais aussi INSTALLED_APPLICATIONS avec les chemins d'accès corrects à tous les fichiers models.py.

Il est possible de lancer votre propre solution pour utiliser syncdb sans settings.py, mais cela nécessite des connaissances avancées de Django. Bien sûr, vous n'avez pas besoin d'utiliser syncdb; les tables peuvent être créées indépendamment des modèles. Mais c'est un aspect de l'ORM qui n'est pas disponible à moins que vous ne mettiez un peu d'effort dans la configuration.

Deuxièmement, réfléchissez à la manière dont vous créeriez vos requêtes dans la base de données avec l’appel standard Model.objects.filter(). Si cela est fait dans le cadre d'une vue, c'est très simple: construisez la variable QuerySet et affichez les instances. Par exemple:

tag_query = Tag.objects.filter( name='stackoverflow' )
if( tag_query.count() > 0 ):
    tag = tag_query[0]
    tag.name = 'stackoverflowed'
    tag.save()

Nice, simple et propre. Maintenant, sans le béquille du système de chaînage demande/réponse de Django, vous devez initialiser la connexion à la base de données, effectuer la requête, puis fermer la connexion. Ainsi, l'exemple ci-dessus devient:

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()

La gestion de la connexion à la base de données peut également être effectuée via les signaux Django. Tout ce qui précède est défini dans Django/db / init . Py . D'autres ORM ont également ce type de gestion de connexion, mais vous n'avez pas besoin de creuser dans leur source pour savoir comment le faire. Le système de gestion des connexions de SQL Alchemy est documenté dans les tutoriels } et ailleurs.

Enfin, vous devez garder à l'esprit que l'objet de connexion à la base de données est local pour le thread actuel à tout moment, ce qui peut ou non vous limiter, selon vos besoins. Si votre application n'est pas sans état, comme Django, mais persistante, vous risquez de rencontrer des problèmes de thread.

En conclusion, c'est une question d'opinion. À mon avis, les limitations et la configuration requises pour l'ORM de Django distinct du cadre constituent un fardeau trop lourd. Il existe des solutions ORM dédiées parfaitement viables disponibles ailleurs et conçues pour une utilisation en bibliothèque. Django n'est pas. 

Ne croyez pas que tout ce qui précède montre que je n'aime pas Django et que tout fonctionne bien, j'aime vraiment beaucoup Django! Mais je suis réaliste quant à ses capacités et être une bibliothèque ORM n'en fait pas partie.

P.S. La prise en charge de plusieurs connexions à la base de données est en cours travaillé . Mais ce n'est pas là maintenant.

11
Shane Breatnach

Si vous aimez l'ORM de Django, il est très simple de l'utiliser "autonome"; J'ai écrit plusieurs techniques d'utilisation de parties de Django en dehors d'un contexte Web , et vous êtes libre de les utiliser (ou de les rouler vous-même).

Shane ci-dessus semble être un peu mal informé sur ce point et quelques autres points - par exemple, Django peut créer plusieurs bases de données différentes, il ne s'agit tout simplement pas de par défaut faire un gestionnaire personnalisé sur les modèles qui utilisent autre chose que la base de données "principale", quelque chose qui n'est pas trop difficile et il y a des recettes qui flottent pour cela). Il est vrai que Django lui-même ne gère pas la connexion/le regroupement de connexions, mais personnellement, j’ai toujours utilisé des outils externes pour cela (par exemple, pgpool, ce qui est plus difficile que tout ce qui a été construit dans un ORM).

Je suggérerais de passer un peu de temps à lire et éventuellement à essayer quelques recherches Google probables (par exemple, le message auquel je vous ai lié apparaît comme le premier résultat de "script Django autonome") pour avoir une idée de ce qui conviendra le mieux à votre situation. les besoins et les goûts - c'est peut-être l'ORM de Django qui ne vous convient pas, et vous ne devriez pas l'utiliser s'il ne l'était pas, mais malheureusement, il y a beaucoup de désinformation qui trouble les eaux.

Modification pour répondre à Shane:

Encore une fois, vous semblez être mal informé: SQLAlchemy doit être configuré (c.-à-d. Quelle base de données utiliser, comment se connecter, etc.) avant de pouvoir lancer des requêtes, alors comment Django a-t-il besoin d'une configuration similaire (réalisée via votre choix de méthodes - vous n'avez pas vous devez disposer d'un fichier de paramètres Django complet) aucun inconvénient?

En ce qui concerne le support de bases de données multiples, vous semblez confus: le support est là à un niveau bas. L'objet de requête - pas QuerySet, mais l'objet Query sous-jacent qu'il va exécuter sait à quelle base de données il se connecte et accepte une connexion à la base de données comme l'un de ses arguments d'initialisation. Dire à un modèle d'utiliser une base de données et un autre modèle d'en utiliser un autre est aussi simple que de configurer une méthode sur un gestionnaire, qui transfère les informations de connexion appropriées dans la variable Query. Certes, il n'y a pas d'API de niveau supérieur pour cela, mais ce n'est pas la même chose que "pas de support" et pas plus que "nécessite un code personnalisé" (à moins que vous ne discutiez de la configuration explicite de plusieurs DB dans SQLAlchemy, requis si vous voulez plusieurs DB, est aussi "code personnalisé").

Quant à savoir si vous vous retrouvez indirectement en utilisant des éléments qui ne figurent pas dans Django.db, eh bien, et alors? Le fait que Django.db importe des bits de, disons, Django.utils, car il existe des structures de données et d'autres bits de code utiles pour plus qu'un simple ORM, cela me convient personnellement; on pourrait aussi bien se plaindre si quelque chose a des dépendances externes ou utilise des bibliothèques Python standard au lieu d’être autonome à 100%.

87
James Bennett

(Je signale ma solution parce que ma question était un doublon)

Ah ok je l'ai compris et je posterai les solutions pour tous ceux qui tentent de faire la même chose.

Cette solution suppose que vous souhaitiez créer de nouveaux modèles.

Commencez par créer un nouveau dossier pour stocker vos fichiers. Nous l'appellerons "standAlone". Dans "standAlone", créez les fichiers suivants:

__init__.py
myScript.py
settings.py

De toute évidence, "myScript.py" peut être nommé comme vous le souhaitez. 

Ensuite, créez un répertoire pour vos modèles.

Nous nommerons notre répertoire de modèles "myApp", mais nous réaliserons qu'il s'agit d'une application Django normale au sein d'un projet. Par conséquent, attribuez-lui un nom correspondant à la collection de modèles que vous écrivez. 

Dans ce répertoire, créez 2 fichiers: 

__init__.py
models.py

Vous aurez besoin d’une copie de manage.py d’un projet Django existant ou vous pouvez simplement en obtenir une copie depuis votre chemin d’installation Django:

Django\conf\project_template\manage.py

Copiez le fichier manage.py dans votre répertoire/standAlone. Ok donc vous devriez maintenant avoir la structure suivante:

\standAlone
    __init__.py
    myScript.py
    manage.py
    settings.py
\myApp
    __init__.py
    models.py

Ajoutez ce qui suit dans votre fichier myScript.py:

# settings.py
from Django.conf import settings

settings.configure(
    DATABASE_ENGINE    = "postgresql_psycopg2",
    DATABASE_NAME      = "myDatabase",
    DATABASE_USER      = "myUsername",
    DATABASE_PASSWORD  = "myPassword",
    DATABASE_Host      = "localhost",
    DATABASE_PORT      = "5432",
    INSTALLED_APPS     = ("myApp")
)

from Django.db import models
from myApp.models import *

et ajoutez ceci à votre fichier settings.py:

    DATABASE_ENGINE    = "postgresql_psycopg2"
    DATABASE_NAME      = "myDatabase"
    DATABASE_USER      = "myUsername"
    DATABASE_PASSWORD  = "myPassword"
    DATABASE_Host      = "localhost"
    DATABASE_PORT      = "5432",
    INSTALLED_APPS     = ("myApp")

et enfin votre myApp/models.py:

# myApp/models.py
from Django.db import models

class MyModel(models.Model):
     field = models.CharField(max_length=255)

et c'est tout. Maintenant, pour que Django gère votre base de données, dans la commande Invite, accédez à notre répertoire/standalone et exécutez: 

manage.py sql MyApp
10

Vous pouvez certainement utiliser différentes parties de Django de manière autonome. Après tout, il s’agit simplement d’une collection de modules Python, que vous pouvez importer dans n’importe quel autre code que vous souhaitez utiliser.

Je vous recommande également de regarder SQL Alchemy si vous êtes seulement après le côté ORM.

9
Andy Hume

J'utilise Django ORM sans fichier de paramètres. Voici comment: 

Dans le fichier de lancement de l'application autonome: 

from Django.conf import settings
from Django.core.management import execute_from_command_line

#Django settings
settings.configure(DEBUG=False,
    DATABASES = {
        'default': {
            'ENGINE': 'Django.db.backends.sqlite3',
            'NAME': '/path/to/dbfile',
            'USER': '',
            'PASSWORD': '',
            'Host': '',
            'PORT': '',
        }
    },
    INSTALLED_APPS = ('modelsapp',)
)

if not os.path.exists('/path/to/dbfile'):
    sync = ['manage.py', 'syncdb']
    execute_from_command_line(sync)

Vous avez maintenant besoin d’un dossier ./modelsapp contenant un __init__.py et un models.py. La configuration utilise sqlite pour des raisons de simplicité, mais elle pourrait utiliser l’un des backends de la base de données.

Structure du dossier: 

./launcher.py
./modelsapp
    __init__.py
    models.py

Notez qu'il n'est pas nécessaire d'avoir un fichier manage.py correct. Le import execute_from_command_line le trouve simplement.

5
RobotHumans

Je recommande SQLAlchemy . Il devrait faire tous les trucs ORM, ainsi que des trucs SQL de base.

4
dwc

Cet exemple est aussi simple que possible. J'ai déjà une application Django appelée thab up and running. Je souhaite utiliser Django Orm dans des scripts python autonomes et utiliser les mêmes modèles que ceux que j'utilise pour la programmation Web. Voici un exemple:

# nothing in my sys.path contains my Django project files
import sys
sys.path.append('c:\\apython\\thab')  # location of Django app (module) called thab          where my settings.py and models.py is
# my settings.py file is actualy in c:\apython\thab\thab
from thab import settings as s  # need it because my database setting are there
dbs = s.DATABASES
from Django.conf import settings
settings.configure(DATABASES=dbs) # configure can only be called once
from thab.models import *
boards = Board.objects.all()
print 'all boards:' + str(boards) # show all the boards in my board table
2
Jim Paul

Jetez un coup d’œil à Django-standalone , ce qui rend cette configuration assez facile.

J'ai aussi trouvé cette entrée de blog très utile.

2
Ber
import Django
from Django.conf import settings
from backend_mock.admin import settings as s
settings.configure(
    DATABASES=s.DATABASES,
    INSTALLED_APPS=('backend_mock.admin.mocker', )
)
Django.setup()

jetez un oeil à cela, cela fonctionne pour Django version gte 1.8.x

1
Pengfei.X

Je suis probablement en retard avec ma réponse, mais il vaut mieux tard que jamais.

Essayez ce paquet simple: https://github.com/serglopatin/Django-models-standalone

Comment utiliser:

  1. télécharger

  2. installer

    python setup.py install
    
  3. créer un projet

    Django-models-standalone startproject myproject
    
  4. ajustez les fichiers settings.py (DATABASES) et models.py, puis migrez si les tables ne sont pas créées

  5. utiliser les modèles Djando dans votre application (exemple.py)

1
Sergey

Utilisation de Django 2.0 ORM - Un fichier requis

from myproject.config import parse_config
from Django import setup as Django_setup
from Django.conf import settings as Django_settings

"""
Requirements:
  ODBC Driver: https://www.Microsoft.com/en-ca/download/details.aspx?id=36434
  Django Engine: https://pypi.org/project/Django-pyodbc-Azure/
"""

config = parse_config()
Django_settings.configure(
    DEBUG=True,
    DATABASES={
        'default': {
            'ENGINE': 'sql_server.pyodbc',
            'NAME': config.database_name,
            'Host': config.database_server,  # exclude '\\MSSQLSERVER'
            'USER': config.database_username,
            'PASSWORD': config.database_password,
            'PORT': '',
            'AUTOCOMMIT': False,
            'OPTIONS': {
                'driver': 'ODBC Driver 11 for SQL Server',
            },
        },
    })
Django_setup()


from Django.db import models

class Foo(models.Model):
    name = models.CharField(max_length=25)

    class Meta:
        app_label = 'myapp'  # each model will require this
1
Scott P.

C'est ce qui a fonctionné pour moi dans Django> 1.4

En supposant que votre script autonome soit votre DIR de projet Django.

Copiez simplement ceci dans un fichier conf.py (vous pouvez lui donner n'importe quel nom).

import os
import sys
import Django

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR) 
#sys.path.append('c:\\apython\\thab')
 # location of Django app (module) called thab          where my settings.py and models.py is
# my settings.py file is actualy in c:\apython\thab\thab
from elsaserver import settings as s  # need it because my database setting are there
dbs = s.DATABASES
from Django.conf import settings
settings.configure(
    DATABASES=dbs,
    INSTALLED_APPS=('core.apps.CoreConfig', )) #add all the apps you need here
Django.setup()

Importez ensuite le fichier conf.py dans votre script python.

Voici la structure du projet:

mydjangoproject
    |
    > app1
    > core
    > app2
    > standalone
    | | __init__.py  
    | | conf.py  
    | | myscript.py
    > manage.py
1
Therese Elsa

Puis-je utiliser uniquement la partie ORM pour obtenir des classes mappées sur des tables de base de données et savoir lire/écrire à partir de ces tables?

Oui, vous pouvez.

Voici une explication propre et courte sur l'utilisation de Django abstraction de modèles et de bases de données: https://stackoverflow.com/a/49515366/2682613

Version Django: 2.0.2

0
IvanJijon

Vous pouvez l'utiliser en dehors d'un projet Django. Mais il y a des choses que vous devriez connaître.

1. Plusieurs routeurs de base de données.

Un routeur ressemble à:

class Router(object):
    app_label = ''

    def db_for_read(self, model, **hints):
        if model._meta.app_label == self.app_label:
            return self.app_label
        return None

    def db_for_write(self, model, **hints):
        if model._meta.app_label == self.app_label:
            return self.app_label
        return None

    def allow_relation(self, obj1, obj2, **hints):
        if obj1._meta.app_label == self.app_label or obj2._meta.app_label == self.app_label:
           return True
        return None

    def allow_migrate(self, db, app_label, model=None, **hints):
        if app_label == self.app_label:
            return db == self.app_label
    return None

Vous pouvez utiliser la classe méta pour créer dynamiquement un routeur.

def add_db(db_conf):
    app_label = 'al_' + str(uuid4())

    settings.DATABASES[app_label] = db_conf

    router_class_name = 'Router' + app_label.capitalize()
    setattr(
        settings,
        router_class_name,
        type(router_class_name, (Router,), dict(app_label=app_label)),
    )
    settings.DATABASE_ROUTERS.append(
        '.'.join([settings.__name__, router_class_name])
    )
    connections.close_all()
return app_label

2. Paramètres Django.

la clé la plus importante est TIME_ZONE. DatetimeField et DateField y sont associés. Le paramètre le plus simple devrait être:

SECRET_KEY = 'secret'
DATABASES = {'default': {}}
DATABASE_ROUTERS = []
TIME_ZONE = None

3. close_old_connections.

Le framework par défaut de Django exécute close_old_connections dans chaque middleware de requête pour éviter que " mysql ne disparaisse ".


PS: J'ai écrit un paquet pour utiliser Django orm pas dans un projet Django classique, https://github.com/jdxin0/Django_db(https://github.com/jdxin0/Django_db ) . Mais vous devriez toujours faire attention aux trois problèmes ci-dessus.Mon paquet utilise meta class pour résoudre multi db, définissez TIME_ZONE=None et laissez close_old_connections à utilisateur.

0
jdxin0