2017-10-13 1 views
3

Ich versuche zu verstehen, wie ORMs Tabellenspalten über ein Klassenattribut auflösen können, ohne explizit Tabellen- und Spaltennamen anzugeben.Wie bindet eine ORM-Modelldefinition Spaltenattribute an tatsächliche Spalten?

from orm import Column 

class Car(Model): 
    id = Column() 

Abfragen sind dann in der Lage, dies zu tun:

Car.select().where(Car.id == 7) 

Ich verstehe, dass Spalte ein Verfahren zum __eq__ Operator definiert, aber wie wäre eine Spalte Beispiel weiß, dass es in der Klasse bezieht Car und Attribut id (Angenommen, diese werden standardmäßig für Tabellen- und Spaltennamen verwendet)

Ich lerne viel über Python, indem ich eingrabe, wie ORM-Bibliotheken funktionieren!

Antwort

2

In SqlAlchemy und DJango ORM ist die Basisklasse (Model hier) an eine Metaklasse oder eine Factory-Methode (wie __new__) gebunden, die Introspektion durchführt.

Hier ist, wie man mit einer Funktion (einfachere Lösung) wiedergeben kann:

class Model(): 
    pass 


class Column(): 
    def __init__(self, name=None): 
     self.name = name 


def setup_class(cls): 
    for name, value in cls.__dict__.items(): 
     if isinstance(value, Column): 
      attr = getattr(cls, name) 
      attr.name = attr.name or name 

Diese setup_class Funktion des cls Klasse und das Setup des Name Attribut introspect wenn es leer ist oder None, zum Beispiel :

class Car(Model): 
    id = Column() 


from pprint import pprint 
pprint(Car.id.name) 
# -> None 

setup_class(Car) 
pprint(Car.id.name) 
# -> 'id' 

bearbeiten

Implementierungsbeispiel mit metaclass:

class Column(): 
    def __init__(self, name=None): 
     self.name = name 


class MyMeta(type): 
    def __new__(cls, name, bases, attrs): 
     for name, col in attrs.items(): 
      if isinstance(col, Column): 
       col.name = col.name or name 
     return super(MyMeta, cls).__new__(cls, name, bases, attrs) 


class Model(metaclass=MyMeta): 
    pass 


class Car(Model): 
    id = Column() 


import pprint 
pprint.pprint(Car.id.name) 
# -> 'id' 

Natürlich ist das nicht genug. Sie müssen verstehen, dass Column ein descriptor ist. Dieser Deskriptor wird zum Erstellen der SQL-Abfragen verwendet.

+0

Ich wusste, dass mir etwas Magie fehlte. Hatte Metaklassen noch nie zuvor gesehen. Danke Laurent! – pybot

Verwandte Themen