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.
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`.
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é.
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'
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.
{" default ": 1}
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 **
Metaclass .__ nouveau __
Classe .__ nouveau __
Classe .__ init __
Recommended Posts