La fonctionnalité ORM de Django est excellente, mais lorsque vous essayez de créer un modèle pour une table légèrement différente, telle qu'une table créée dynamiquement ou une table dans un schéma postgres spécifique, il n'y a pas beaucoup d'informations.
De plus, si vous essayez de faire quelque chose d'un peu compliqué, comme détourner la table créée et créer une table avec la même définition dans un autre schéma, il faut du temps pour enquêter et le processus de développement s'arrête pendant quelques jours.
Cet article est un récit de la lutte pour atteindre les objectifs suivants face à ces défis.
** <Ce que vous voulez réaliser> **
--Je veux créer un modèle qui a la même définition qu'un modèle existant mais qui ne diffère que dans le schéma, en détournant le modèle existant. --Je souhaite utiliser le modèle créé pour ** dynamiquement ** créer une table dans un schéma différent du modèle créé.
En bref, bien que ce soit une exigence légèrement compliquée, la fonction ORM utilisant la classe Model de Django est excellente, je veux donc maximiser les avantages de la création de table, de l'enregistrement des enregistrements, de la recherche, etc.
--Une des utilisations de schéma décrites dans le document PostgreSQL 10.5 "Une base de données est utilisée par de nombreux utilisateurs. C'est parce que nous voulons réaliser "afin qu'ils puissent être utilisés sans interférer les uns avec les autres". Cette fois, nous visons à réaliser un service d'analyse qui puisse être utilisé par différents utilisateurs, mais afin d'éliminer les interférences entre les données utilisateur, nous voulons préparer un schéma avec la même structure de table pour chaque utilisateur.
L'environnement cette fois est le suivant.
En conclusion, cela a été possible en appliquant les références. Les détails sont décrits ci-dessous.
Premièrement, pour l'explication suivante, un exemple de modèle qui est une source de détournement est le suivant.
app/models/model.py
class Compound(models.Model):
name = models.CharField(max_length=1024)
smiles = models.CharField(max_length=4000, null=True)
standard_inchi = models.CharField(max_length=4000, default=None, null=True)
mol = models.TextField(null=True)
image = models.BinaryField(null=True)
Puisque le modèle de la source de diversion est sous le contrôle de la migration de Django, vous devriez pouvoir créer une table pour le modèle en effectuant une migration, migrez. La table sera alors créée dans le schéma public à moins que vous ne définissiez des paramètres spéciaux.
Ensuite, la fonction qui est la clé de cette heure sera expliquée. Normalement, dans Django, il est nécessaire de créer au préalable une classe de modèle dans la source, mais cette fois, reportez-vous à Modèles dynamiques et créez le modèle souhaité. J'ai préparé une fonction pour créer dynamiquement une classe. Plus précisément, un nouveau modèle peut être créé en spécifiant le schéma, le nom de la table et la classe de modèle de la source de déviation. La source est la suivante. Il convient de noter que, où peuvent être créés pour la fonction, mais sont définis dans le même module et la source de déviation actuelle.
app/models/model.py
def create_model_by_prototype(model_name, schema_name, table_name, prototype):
import copy
class Meta:
pass
setattr(Meta, "db_table", schema_name + "\".\"" + table_name)
fields = {}
for field in prototype._meta.fields:
fields[field.name] = copy.deepcopy(field)
attrs = {'__module__': "app.models.models", 'Meta': Meta}
attrs.update(fields)
model = type(model_name, (models.Model,), attrs)
return model
Nous examinerons des exemples d'utilisation spécifiques plus tard et expliquerons brièvement la source.
Meta``` --Dans
setattr```, le nom de table spécifié par l'argument est défini pour l'attribut "db_table" qui représente le nom de table géré par Model.
--Dans la boucle '' pour champ dans prototype._meta.fields:
, nous nous préparons à définir le champ du modèle à détourner vers le champ du modèle à créer cette fois.
--Enfin, avec
type (model_name, (models.Model,), attrs) ``, une nouvelle classe Model est générée et renvoyée en fonction des informations d'attribut préparées.Maintenant, voyons l'image d'utilisation de la fonction en utilisant la fonction créée par la pratique avec django shell.
Ceci est omis car il n'exécute que les makemigrations de Django et migre.
Le schéma de stockage de la nouvelle table était cette fois gênant, je l'ai donc créé en me connectant directement à Postgres. Le nom du schéma est user01.
create schema user01;
$ python manage.py shell
Python 3.7.6 | packaged by conda-forge | (default, Jun 1 2020, 18:11:50) [MSC v.1916 64 bit (AMD64)]
Type 'copyright', 'credits' or 'license' for more information
IPython 7.16.1 -- An enhanced Interactive Python. Type '?' for help.
Ensuite, importez les modules requis pour utiliser la fonction.
from chempre.models.models import Compound
from chempre.models import models
Maintenant, créons un modèle dynamiquement en utilisant la fonction créée. Ici, un modèle appelé Compound est utilisé et une table appelée my_compound avec la même définition est créée dans le schéma user01 créé précédemment.
model= models.create_model_by_prototype("MyCompound", "user01", "my_compound", Compound)
Ensuite, créez une table correspondant à Model. Étant donné que ce modèle n'est pas géré par migration, il sera créé différemment que d'habitude. La procédure est la suivante.
from django.db import connection
with connection.schema_editor() as schema_editor:
schema_editor.create_model(model)
Cela créera une table dans le schéma user01. Quand je me connecte à Postgres avec psql, il est certainement créé.
Ensuite, enregistrons les données. Comme il était difficile de spécifier le champ, je crée ici un enregistrement avec uniquement le champ de nom défini.
model.objects.create(name='compound name')
Cherchons et vérifions si la table a été créée.
compound=model.objects.get(id=1)[
print(compound.name)
Si vous êtes enregistré, vous devriez voir la valeur "nom du composant". De plus, lorsque je me connecte à Postgres avec psql, un enregistrement est certainement créé.
J'ai pu réaliser en toute sécurité tout ce que je souhaitais à l'origine. Je veux produire en masse le modèle Gangan de cette manière et profiter de la vie Django. Django a beaucoup de tactiques et beaucoup à retenir, mais il n'a pas la robustesse et la rigidité qui sont typiques de ce type de framework, et il semble qu'il puisse être personnalisé de manière flexible.
Recommended Posts