简体   繁体   中英

How does Base.metadata work in Sqlalchemy?

Code/Example

from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

If I run print(Base) then I get result:

<class 'sqlalchemy.ext.declarative.api.Base'>

(Ie Base is a class created by the function declarative_base ).

If I run print(Base.metadata) then I get

Metadata(bind=engine(postgres//:user:password@host/database))

But exactly how does print(Base.metadata) even run if Base is a class and metadata is an object?

How are the two connected?

I could understand if metadata was a class attribute but from what I understand it is not so how does this work?

Is there something in python syntax that I have missed?

Looking in metadata code:

from sqlalchemy import MetaData
metadata = MetaData()

What is here the definition of metadata and MetaData ? Are they both objects? Is MetaData() a function or something else?

According to SQLAlchemy documentation MetaData is:

a container object that keeps together many different features of a database (or multiple databases) being described.

But if it is an object so then how can it be run as something similar to a function: Metadata() ?

Summary:

  • How are Base and metadata connected if one is a class and the other is an object?
  • How can the command ( Base.metadata ) be run?
  • What is the difference between metadata and MetaData and what is the MetaData() definition?

You are overthinking this. In Python everything is an object . Classes, functions, instances, numbers, strings, lists, dictionaries, modules, ..., everything .

The SQLAlchemy objects you are looking at are no different, there really is nothing special about these.

Yes, the declarative_base() function returns a new class object, one you assigned to the name Base . That class has attributes, and one of those attributes is named metadata . All Python classes have attributes, they can point to any object you like:

class Foo:
    def __init__(self, name):
        self.name = name

    def print(self):
        print(f"Hello, {self.name}!")

class Bar:
    spam = Foo("World")

The above class Bar has an attribute spam that is an instance of the class Foo . You can call methods on it:

>>> Bar.spam.print()
Hello, World!

Note that Bar is still a class, and Bar.spam is an instance of the Foo class:

>>> Bar
<class '__main__.Bar'>
>>> Bar.spam
<__main__.Foo object at 0x10d43c650>
>>> type(Bar.spam)
<class '__main__.Foo'>

Because Bar is just another object, you can also pass it around, put it in a list, or return it from a function. declarative_base() constructed a class object for you, with attributes, and returned it to the caller.

Similarly, Base.metadata is just an instance of the MetaData class:

>>> type(Base.metadata)
<class 'sqlalchemy.sql.schema.MetaData'>

and so is your metadata = MetaData() object.

Note that if you only run Base = declarative_base() and nothing else, the MetaData instance is not actually showing any database connection information:

>>> Base.metadata
MetaData(bind=None)

That's because you didn't actually connect the metadata to a database session. Once you start connecting a database with an engine and start using the models you define by subclassing Base , the metadata object at some point will need to know more about the specifics of the database (such as what kind of SQL dialect is supported) and it'll be bound by SQLAlchemy.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM