Dans la métaclasse python, transmettez l'opérateur de comparaison sous forme de chaîne à la méthode ORM pour construire la clause where.

J'ai créé mon propre mappeur ORM, mais j'ai implémenté le processus de transmission de l'opérateur de comparaison comme argument à la méthode where. Ce serait bien si vous pouviez imaginer comment l'utiliser comme suit. Vous pouvez spécifier chaque condition de la clause where de manière plus intuitive.

Session.select('coulmn_name1', 'coulmn_name2').where(Model.id > 1, _and, Model.name == "Mike")

Si vous passez Model.id> 1, comme argument, True ou False est généralement passé et ** id signifie supérieur à 1 ** ne peut pas être passé. Cependant, si vous réécrivez la méthode spéciale, vous pouvez transmettre l'argument sans le traiter comme opérateur de comparaison.

Dans cette méthode where, seul le processus de «retour de la clause where sous forme de chaîne de caractères» est implémenté. C'est simple à faire, mais connaître cette implémentation s'est avéré utile pour la métaprogrammation.

Je pense que des informations utiles peuvent être obtenues pour ces personnes. Cependant, cet article n'explique pas la métaprogrammation elle-même. Si vous connaissez la métaprogrammation et que vous souhaitez voir un exemple, cet article vous aidera.

Comment faire votre propre modèle

Si vous disposez d'une table qui gère les personnes appelées Person, déclarez le modèle Person dans la classe comme suit.

from model_base import *

class Person(ModelBase):
    id = {'default': 1}
    name = {'default': 'Mike'}

Tout ce que vous avez à faire est de déclarer les noms de colonnes requis dans votre modèle. Pour la valeur initiale, spécifiez l'option dans le dictionnaire. Cette fois, nous n'avons que l'option defalut. Tant que vous héritez de ModelBase, le modèle sera assemblé automatiquement.

Lorsque la classe Person est chargée, les champs de classe, ʻid et name, ne contiennent pas de dictionnaires tels que {'default': 1}. L'objet de classe de colonne est automatiquement inclus par la classe méta. Si vous voulez voir default, écrivez simplement pseron_instance.id.default`.

Nom de variable traité comme un nom de colonne

Déclarez le nom de la colonne sans _ (trait de soulignement) au début du champ de classe. Si vous utilisez _ (trait de soulignement) comme préfixe, il ne sera pas reconnu comme une colonne, veuillez donc préfixer la méthode ou le champ requis avec _ (trait de soulignement) comme privé.

En fait utiliser

Cette fois, la méthode where renvoie la clause where assemblée sous forme de chaîne de caractères.

from person import *

if __name__ == '__main__':
    db_manager = DBManager()

    #Assemblage de la clause where
    db_manager.where(Person.id > 1, "or", Person.name == 'Mike')
    #Facile à taper si préparé avec des variables locales
    _and = "and"
    _or = "or"
    db_manager.where(Person.id > 1, _and, Person.name == 'Mike')

    #Vérifiez la valeur par défaut
    person_A = Person()
    print("person_A.id = %s" % person_A.id)
    print("person_A.name = %s" % person_A.name)

    # Model.Objet Colm pour id, modèle.Erreur car l'ID contient la valeur de la colonne
    person_A = "Jane"
    print(Person.name.default)
    # print(person_A.name.default)
    # => AttributeError: 'str' object has no attribute 'name'

Module pour assembler le modèle

Il y a quatre cours à préparer.

class Column():

    def __init__(self, column_name, dict):
        #Conserver les noms de colonne dans les variables de classe
        self.column_name = column_name

        #Défini lors de la réception de la valeur de réglage de chaque colonne
        if dict is not None:
            for key, value in dict.items():
                if key == "default":
                    self.default = value

    def __setattr__(self, key, value):
        #Vous pouvez vérifier le type de colonne en vérifiant la valeur et en lançant une erreur.
        self.__dict__[key] = value

    #Opérateur de comparaison de surcharge
    def __eq__(self, other):
        return "%s = %s" % (self.column_name, other)

    def __ne__(self, other):
        return "%s != %s" % (self.column_name, other)

    def __lt__(self, other):
        return "%s < %s" % (self.column_name, other)

    def __gt__(self, other):
        return "%s > %s" % (self.column_name, other)

    def __le__(self, other):
        return "%s <= %s" % (self.column_name, other)

    def __ge__(self, other):
        return "%s >= %s" % (self.column_name, other)

class MetaModel(type):
    def __new__(cls, cls_name, cls_bases, cls_dict):
        for key, value in cls_dict.items():
            #Extraire uniquement les attributs publics
            if not(key.startswith("_")):
                #colonne(Variables de classe de modèle)Peut récupérer la valeur initiale de
                #Conserver le nom de la variable dans le champ de colonne
                cls_dict[key] = Column(key, value)
        return super().__new__(cls, cls_name, cls_bases, cls_dict)

class ModelBase(metaclass=MetaModel):
    #Appelé immédiatement après la création d'une instance
    def __init__(self):
        #Définir la valeur par défaut définie pour l'objet Column
        class_dict = self.__class__.__dict__
        for column_key, column_value in class_dict.items():
            #Extraire uniquement les attributs publics
            if not(column_key.startswith("_")):
                setattr(self, column_key, column_value.default)

class DBManager():
    def where(self, *args):
        statement = "WHERE"
        for arg in args:
            if arg.upper() in ["AND", "OR"]:
                statement += " %s " % arg.upper()
            else:
                statement += " %s " % arg
        print(statement)

J'ai défini la métaclasse sur ModelBase. Ceci afin que vous n'ayez qu'à écrire MetaModel au lieu d'écrire metaclass = MetaModel dans la sous-classe. De plus, le traitement commun du modèle est décrit ici.

Les informations de chaque colonne sont gérées par une instance d'une classe dédiée. En faisant cela, vous pouvez implémenter un traitement automatique tel que la validation pour chaque colonne. S'il n'y a pas de classe dédiée, classe Column, vous ne pouvez transmettre que des valeurs de colonne.

#Sans ModelBase
class MyModel(metaclass=MetaModel):
    pass

#Si vous avez ModelBase
class MyModel(ModelBase):
    pass

Même si vous n'instanciez pas Person, ModelMeta, qui est la métaclasse de Person, sera exécuté lors du chargement de Person. Par conséquent, un objet Column (instance) est créé dynamiquement et défini dans l'id et le nom des champs de classe de Person. Cette colonne contient la valeur par défaut de chacun dans la valeur par défaut du membre d'instance.

Flux que l'objet Column est défini dans le champ de classe de Person

  1. Chargez la classe Person
  2. MetaModel est exécuté
  3. Recevez la valeur initiale attendue du champ de classe de la personne. Exemple: {" default ": 1}
  4. Créez un objet Column avec {"default": 1} comme argument
  5. Enregistrez un objet Column dans le dict, qui est une liste d'attributs de classe.
  6. Laissez la définition des champs de classe au type de métaclasse, qui est le parent de MetaModel.
  7. Définissez un objet Column avec le type de métaclasse sur le champ de classe Person

Différence entre la méta classe et la nouvelle classe

Une métaclasse appelée MetaModel peut également être définie comme une classe régulière au lieu d'être une métaclasse. Dans ce cas, vous pouvez simplement utiliser ModelBase. Cependant, dans ce cas, vous devez créer une instance une fois. Je pense que vous devriez écrire l'instanciation à la toute fin du code source afin qu'elle soit exécutée automatiquement lorsque le module est chargé. Mais je ne pense pas que ce soit une bonne idée.

class Column():
    pass

class MetaModel(type):
    pass

class DBManager():
    pass

class ModelBase():
	pass

ModelBase()`

La raison pour laquelle vous devez créer une instance une fois est que __new__ effectue le processus de création d'une instance. (Strictement juste avant. Je laisse la génération séparément.) L'important ici est de savoir quel genre d'instance il s'agit. Une métaclasse est une classe pour créer une classe, c'est-à-dire une instance de la métaclasse. D'autre part, une instance de classe simple est un objet créé à partir d'une classe normale. Habituellement, une instance est le produit d'une classe, mais lorsque nous parlons de relations, nous pouvons utiliser l'instance d'expression dans les métaclasses et les classes.

Les deux relations suivantes sont toutes deux générées avec le plan directeur. Le côté droit peut être vu comme une instance.

Dans cet esprit, si vous voyez que __new__ est ce que vous faites lorsque vous créez une instance, la simple différence entre une métaclasse et une classe__new__ est l'ordre de traitement. Organisez le dernier ordre d'exécution pour terminer.

** Ordre d'exécution **

  1. Metaclass .__ nouveau __
  2. La classe est créée
  3. Classe .__ nouveau __
  4. Une instance est créée
  5. Classe .__ init __
  6. Les variables d'instance sont définies

Recommended Posts

Dans la métaclasse python, transmettez l'opérateur de comparaison sous forme de chaîne à la méthode ORM pour construire la clause where.
Comment utiliser la méthode __call__ dans la classe Python
[Introduction à Python] Comment utiliser l'opérateur in dans l'instruction for?
Obtenez la formule dans le fichier Excel sous forme de chaîne en Python
Fonction Eval () qui calcule une chaîne de caractères comme expression en python
Comment saisir une chaîne de caractères en Python et la sortir telle quelle ou dans la direction opposée.
Comment incorporer des variables dans des chaînes python
Pour remplacer dynamiquement la méthode suivante en python
Comment passer le résultat de l'exécution d'une commande shell dans une liste en Python
[Python] J'ai essayé d'obtenir le nom du type sous forme de chaîne de caractères à partir de la fonction type
Vérifiez si la chaîne est un nombre en python
Analyser une chaîne JSON écrite dans un fichier en Python
Comment convertir / restaurer une chaîne avec [] en python
Je souhaite intégrer une variable dans une chaîne Python
[Python] Comment développer des variables dans une chaîne de caractères
[Python] Création d'une méthode pour convertir la base en 1 seconde
[C / C ++] Passez la valeur calculée en C / C ++ à une fonction python pour exécuter le processus et utilisez cette valeur en C / C ++.
[Python] Programmation pour trouver le nombre de a dans une chaîne de caractères qui se répète un nombre spécifié de fois.
Comment compter rapidement la fréquence d'apparition des caractères à partir d'une chaîne de caractères en Python?
Comment passer le résultat de l'exécution d'une commande shell dans une liste en Python (version non bloquante)
Découvrez la largeur apparente d'une chaîne en python
Changer la destination de sortie standard en un fichier en Python
J'ai essayé "Comment obtenir une méthode décorée en Python"
Comment générer une requête à l'aide de l'opérateur IN dans Django
Dans Django, comment abréger la longue chaîne de caractères affichée au milieu ...
"Livre pour former la capacité de programmation à se battre dans le monde" Exemple de solution de code Python --1.6 Compression de chaîne de caractères
Exécutez le code de sortie sur le serveur Web local en tant que "A, faisant semblant d'être B" en python
[Python] Créez un programme qui supprime les sauts de ligne dans le presse-papiers + Enregistrez-vous comme raccourci avec Windows
Comment déterminer l'existence d'un élément sélénium en Python
Comment passer des arguments à un script Python dans SPSS Modeler Batch
Comment transformer une chaîne en tableau ou un tableau en chaîne en Python
[Introduction à Python] Comment fractionner une chaîne de caractères avec la fonction split
[Introduction à Python] Comment générer une chaîne de caractères dans une instruction Print
Comment vérifier la taille de la mémoire d'une variable en Python
python: utilisez les variables définies dans le format de chaîne telles quelles
Comment obtenir une chaîne à partir d'un argument de ligne de commande en python
Spécification du fuseau horaire lors de la conversion d'une chaîne de caractères en type datetime avec python
Comment vérifier la taille de la mémoire d'un dictionnaire en Python
Une fonction qui mesure le temps de traitement d'une méthode en python
Dans la commande python, python pointe vers python3.8
4 méthodes pour compter le nombre d'occurrences d'entiers dans un certain intervalle (y compris la méthode imos) [implémentation Python]
6 façons d'enchaîner des objets en Python
Créer une chaîne aléatoire en Python
Si vous voulez un singleton en python, considérez le module comme un singleton
Remarque: [Python3] Convertissez datetime en chaîne dans le format de votre choix
Comment installer le package python dans un environnement local en tant qu'utilisateur général
Je veux convertir par lots le résultat de "chaîne de caractères" .split () en Python
Je veux colorer une partie de la chaîne Excel avec Python
Comment écrire une chaîne de caractères lorsqu'il y a plusieurs lignes en python
[Introduction à Python] Comment écrire une chaîne de caractères avec la fonction format
[Introduction à Python] Une explication approfondie des types de chaînes de caractères utilisés dans Python!
J'ai fait un programme pour vérifier la taille d'un fichier avec Python
Comment trier en spécifiant une colonne dans le tableau Python Numpy.
Déplacez la tortue à l'endroit où vous cliquez sur la souris avec la tortue en Python
<Python> Un quiz pour convertir par lots les noms de fichiers séparés par une chaîne de caractères spécifique dans le cadre du nom de fichier
Méthode pour créer un environnement Python dans Xcode 6
Ecrire le test dans la docstring python
[Python] Comment inverser une chaîne de caractères
Générer une classe à partir d'une chaîne en Python