The official documentation

Initialization

>>> import sqlalchemy >>> sqlalchemy.__version__ '1.1.4'
> > > the from sqlalchemy. Ext. Declarative import declarative_base # model are inherited from the Base > > > Base = declarative_base () > > > the from sqlalchemy import Column, Integer, String >>> class User(Base): ... __tablename__ = 'users' # specify tablename... . id = Column(Integer, primary_key=True) ... name = Column(String(50)) ... fullname = Column(String(50)) ... password = Column(String(50)) ... . def __repr__(self): ... return "<User(name='%s', fullname='%s', password='%s')>" % ( ... >>> user. __table__ Table('users', MetaData(bind=None)) >>> user. Table('users', MetaData(bind=None)) Column('id', Integer(), table=<users>, primary_key=True, nullable=False), Column('name', String(length=50), table=<users>), Column('fullname', String(length=50), table=<users>), Column('password', String(length=50), table=<users>), schema=None)

Formally create the data table

>>> from sqlalchemy import create_engine # create_engine("mysql://root:root@localhost:3306/python? charset=utf8", encoding="utf-8", CREATE TABLE users (id INTEGER NOT NULL AUTO_INCREMENT, name VARCHAR(50), fullname VARCHAR(50), password VARCHAR(50), PRIMARY KEY (id) )

Creating a Session

The following operations are done through the session object

>>> from sqlalchemy.orm import sessionmaker
>>> Session = sessionmaker(bind=engine)
>>> session = Session()

Adding and Updating Objects

Add a User object

>>> ed_user = User(name='ed', fullname='Ed Jones', password='edspassword')
>>> session.add(ed_user)

The query, filtered by filter_by, lists only the first object to be queried

>>> our_user = session.query(User).filter_by(name='ed').first()
BEGIN (implicit)
INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
('ed', 'Ed Jones', 'edspassword')

SELECT users.id AS users_id,
        users.name AS users_name,
        users.fullname AS users_fullname,
        users.password AS users_password
FROM users
WHERE users.name = ?
 LIMIT ? OFFSET ?
('ed', 1, 0)

>>> our_user
<User(name='ed', fullname='Ed Jones', password='edspassword')>

>>> ed_user is our_user
True

Using add_all, add multiple objects at once

>>> session.add_all([
...     User(name='wendy', fullname='Wendy Williams', password='foobar'),
...     User(name='mary', fullname='Mary Contrary', password='xxg527'),
...     User(name='fred', fullname='Fred Flinstone', password='blah')])

Session is smart, for example, it knows that Ed Jones has been modified

>>> ed_user.password = 'f8s7ccs' # session automatically knows which data has been modified >>> session.dirty IdentitySet([<User(name='ed', fullname='Ed Jones', New IdentitySet([<User(name=' Wendy ', name=' Wendy ', name=' Wendy ', name=' Wendy ', name=' Wendy ', fullname='Wendy Williams', password='foobar')>, <User(name='mary', fullname='Mary Contrary', password='xxg527')>, <User(name='fred', fullname='Fred Flinstone', password='blah')>])

The echo statement indicates that we have updated one object and created three objects.

>>> session.commit()
UPDATE users SET password=? WHERE users.id = ?
('f8s7ccs', 1)
INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
('wendy', 'Wendy Williams', 'foobar')
INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
('mary', 'Mary Contrary', 'xxg527')
INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
('fred', 'Fred Flinstone', 'blah')
COMMIT

>>> ed_user.id
BEGIN (implicit)
SELECT users.id AS users_id,
        users.name AS users_name,
        users.fullname AS users_fullname,
        users.password AS users_password
FROM users
WHERE users.id = ?
(1,)
1

Rolling Back

Since sessions work within a transaction, sometimes we might accidentally delete something by mistake, so we can roll back. We will change the User name of ed_user to Edwardo and add a new User, but remember that we have not committed at this point.

>>> ed_user.name = 'Edwardo' and we'll add another erroneous user, fake_user: >>> fake_user = User(name='fakeuser', fullname='Invalid', password='12345') >>> session.add(fake_user) Querying the session, 4. We can see that they're Flushed into the current transaction:

Check it out

>>> session.query(User).filter(User.name.in_(['Edwardo', 'fakeuser'])).all()
UPDATE users SET name=? WHERE users.id = ?
('Edwardo', 1)
INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
('fakeuser', 'Invalid', '12345')
SELECT users.id AS users_id,
        users.name AS users_name,
        users.fullname AS users_fullname,
        users.password AS users_password
FROM users
WHERE users.name IN (?, ?)
('Edwardo', 'fakeuser')
[<User(name='Edwardo', fullname='Ed Jones', password='f8s7ccs')>, <User(name='fakeuser', fullname='Invalid', password='12345')>]

To rollback, we can see that ed_user’s name is back to Ed and that fake_user has been kicked out of the session

>>> session.rollback()
ROLLBACK

>>> ed_user.name
BEGIN (implicit)
SELECT users.id AS users_id,
        users.name AS users_name,
        users.fullname AS users_fullname,
        users.password AS users_password
FROM users
WHERE users.id = ?
(1,)
u'ed'

>>> fake_user in session
False
issuing a SELECT illustrates the changes made to the database:

When queried at this point, it is obvious that fakeuser has disappeared and the name of the Ed user is changed back to Ed instead of Edwordo

>>> session.query(User).filter(User.name.in_(['ed', 'fakeuser'])).all()
SELECT users.id AS users_id,
        users.name AS users_name,
        users.fullname AS users_fullname,
        users.password AS users_password
FROM users
WHERE users.name IN (?, ?)
('ed', 'fakeuser')
[<User(name='ed', fullname='Ed Jones', password='f8s7ccs')>]

Couting

Used to query the count() operation corresponding to the operation

>>> session.query(User).filter(User.name.like('%ed')).count()
2

>>> from sqlalchemy import func
>>> session.query(func.count(User.name), User.name).group_by(User.name).all()
[(1, u'ed'), (1, u'fred'), (1, u'mary'), (1, u'wendy')]

Querying

A Query Object can be created by using the Query method on the Session

The query is sorted by user ID

>>> for instance in session.query(User).order_by(User.id):
...     print(instance.name, instance.fullname)
ed Ed Jones
wendy Wendy Williams
mary Mary Contrary
fred Fred Flinstone

Query methods can also accept ORM-instrumented descriptors as parameters. The return result is a named tuples

>>> for name, fullname in session.query(User.name, User.fullname):
...     print(name, fullname)
ed Ed Jones
wendy Wendy Williams
mary Mary Contrary
fred Fred Flinstone

The tuples returned by Query are named tuples, supplied by the KeyedTuple class, And can be treated much like an ordinary Python object. The names are The same as The attribute’s name for an attribute, and the class name for a class:

>>> for row in session.query(User, User.name).all():
...    print(row.User, row.name)
<User(name='ed', fullname='Ed Jones', password='f8s7ccs')> ed
<User(name='wendy', fullname='Wendy Williams', password='foobar')> wendy
<User(name='mary', fullname='Mary Contrary', password='xxg527')> mary
<User(name='fred', fullname='Fred Flinstone', password='blah')> fred

You can control the names of individual column expressions using the label() construct, which is available from any ColumnElement-derived object, as well as any class attribute which is mapped to one (such as User.name):

>>> for row in session.query(User.name.label('name_label')).all():
...    print(row.name_label)
ed
wendy
mary
fred

The name given to a full entity such as User, assuming that multiple entities are present in the call to query(), can be controlled using aliased() :

>>> from sqlalchemy.orm import aliased
>>> user_alias = aliased(User, name='user_alias')

>>> for row in session.query(user_alias, user_alias.name).all():
...    print(row.user_alias)
<User(name='ed', fullname='Ed Jones', password='f8s7ccs')>
<User(name='wendy', fullname='Wendy Williams', password='foobar')>
<User(name='mary', fullname='Mary Contrary', password='xxg527')>
<User(name='fred', fullname='Fred Flinstone', password='blah')>

Basic operations with Query include issuing LIMIT and OFFSET, most conveniently using Python array slices and typically in conjunction with ORDER BY:

>>> for u in session.query(User).order_by(User.id)[1:3]:
...    print(u)
<User(name='wendy', fullname='Wendy Williams', password='foobar')>
<User(name='mary', fullname='Mary Contrary', password='xxg527')>
and filtering results, which is accomplished either with filter_by(), which uses keyword arguments:

>>> for name, in session.query(User.name).\
...             filter_by(fullname='Ed Jones'):
...    print(name)
ed

>>> for name, in session.query(User.name).\
...             filter(User.fullname=='Ed Jones'):
...    print(name)
ed

The Query object is fully generative, meaning that most method calls return a new Query object upon which further criteria may be added. For example, to query for users named “ed” with a full name of “Ed Jones”, you can call filter() twice, which joins criteria using AND:

>>> for user in session.query(User).\
...          filter(User.name=='ed').\
...          filter(User.fullname=='Ed Jones'):
...    print(user)
<User(name='ed', fullname='Ed Jones', password='f8s7ccs')>
Common Filter Operators

Some of the most common operators for filter() are listed below

equals: query.filter(User.name == 'ed') not equals: query.filter(User.name ! = 'ed') LIKE: query.filter(User.name.like('%ed%')) IN: query.filter(User.name.in_(['ed', 'wendy', 'jack'])) # works with query objects too: query.filter(User.name.in_( session.query(User.name).filter(User.name.like('%ed%')) )) NOT IN: query.filter(User.name.in_(['ed', 'wendy', 'jack'])) IS NULL: query.filter(User.name == None) # alternatively, if pep8/linters are a concern query.filter(User.name.is_(None)) IS NOT NULL: query.filter(User.name ! = None) # alternatively, if pep8/linters are a concern query.filter(User.name.isnot(None)) AND: # use and_() from sqlalchemy import and_ query.filter(and_(User.name == 'ed', User.fullname == 'Ed Jones')) # or send multiple expressions to .filter() query.filter(User.name == 'ed', User.fullname == 'Ed Jones') # or chain multiple filter()/filter_by() calls query.filter(User.name == 'ed').filter(User.fullname == 'Ed Jones') Note Make sure you use and_() and not the Python and operator! OR: from sqlalchemy import or_ query.filter(or_(User.name == 'ed', User.name == 'wendy')) Note Make sure you use or_() and not the Python or operator! MATCH: query.filter(User.name.match('wendy')) Note match() uses a database-specific MATCH or CONTAINS function; its behavior will vary by backend and is not available on some backends such as SQLite.

Building a Relationship

To create the relationship between objects, let’s create a new Address table. This is a bit more cumbersome than Django’s ORM. We need to set relationship in both classes at the same time

>>> from sqlalchemy import ForeignKey >>> from sqlalchemy.orm import relationship >>> class Address(Base): ... __tablename__ = 'addresses' ... id = Column(Integer, primary_key=True) ... email_address = Column(String(50), nullable=False) ... user_id = Column(Integer, ForeignKey('users.id')) ... . User = relationship(" addresses", back_populates="addresses") # . def __repr__(self): ... Return "<Address(email_address='%s')>" % self.email_address # "Address", order_by=Address.id, back_populates="user") >>> Base.metadata.create_all(engine)

Working with Related Objects

Now that we have created a User, a set of empty addresses corresponding to that User will also be created. The Collection type can be a variety of legal types, such as SET/Dictation (See Customizing Collection Access for Details), but the default Collection is a list.

Now let’s create another user, Jack

>>> jack = User(name='jack', fullname='Jack Bean', password='gjffdd')
>>> jack.addresses
[]

We are free to add Address objects on our User object. In this case we just assign a full list directly:

Now let’s associate the user Jack with some addresses

>>> jack.addresses = [
...                 Address(email_address='[email protected]'),
...                 Address(email_address='[email protected]')]

When using a bidirectional relationship, elements added in one direction automatically become visible in the other direction. This behavior occurs based on Attribute on-change events and is evaluated in Python, without using any SQL: You can now access the user object through the address object

>>> jack.addresses[1]
<Address(email_address='[email protected]')>

>>> jack.addresses[1].user
<User(name='jack', fullname='Jack Bean', password='gjffdd')>

Let’s add and commit Jack Bean to the database. Jack is as well as the two Address members in the corresponding addresses collection are both added to the session at once, using a process known as cascading:

Next Commit saves to the database

>>> session.add(jack)
>>> session.commit()
sqlalchemy.engine.base.Engine INSERT INTO addresses (email_address, user_id) VALUES (%s, %s)
sqlalchemy.engine.base.Engine ('[email protected]', 5L)
sqlalchemy.engine.base.Engine INSERT INTO addresses (email_address, user_id) VALUES (%s, %s)
sqlalchemy.engine.base.Engine ('[email protected]', 5L)
sqlalchemy.engine.base.Engine COMMIT

Querying for Jack, we get just Jack back. No SQL is yet issued for Jack’s addresses:

>>> jack = session.query(User).\ ... filter_by(name='jack').one() >>> jack <User(name='jack', fullname='Jack Bean', Password =' GJFFDD ')> Let's look at the addresses collection. Watch the SQL: >>> jack.addresses [<Address(email_address='[email protected]')>, <Address(email_address='[email protected]')>]

When we accessed the addresses collection, SQL was suddenly issued. This is an example of a lazy loading relationship. The addresses collection is now loaded and behaves Just like an ordinary list. We’ll cover ways to optimize the loading of this collection ina bit.

Delete

Delete. Next we try to delete the Jack object. Note that the address object is not deleted

>>> session.delete(jack) >>> session.query(User).filter_by(name='jack').count() 0 So far, So good. How about Jack's Address Objects? >>> session.query(Address).filter(... Address.email_address.in_(['[email protected]', '[email protected]']) ... ) .count() 2

Uh oh, they’re still there! Analyzing the flush SQL, we can see that the user_id column of each address was set to NULL, But the rows weren’t deleted. Sqlalchemy doesn’t assume that deletes cascade, you have to tell it to do so. Configuring delete/delete-orphan Cascade. We will configure cascade options on the User.addresses relationship to change the behavior. While SQLAlchemy allows you to add new attributes and relationships to mappings at any point in time, in this case the existing relationship needs to be removed, So we need to tear down the mappings completely and start again – we’ll close the Session:

Close to ROLLBACK without committing

>>> session.close()
ROLLBACK

Use a new declarative_base():

>>> Base = declarative_base()

Next we’ll declare the User class, adding in the addresses relationship

including the cascade configuration (we’ll leave the constructor out too):

>>> class User(Base): ... __tablename__ = 'users' ... . id = Column(Integer, primary_key=True) ... name = Column(String(50)) ... fullname = Column(String(50)) ... password = Column(String(50)) ... . addresses = relationship("Address", back_populates='user', ... cascade="all, delete, delete-orphan") ... . def __repr__(self): ... return "<User(name='%s', fullname='%s', password='%s')>" % ( ... self.name, self.fullname, self.password)

Then we recreate Address, 2 noting that in this case we’ve created the Address. User relationship via the user class already:

>>> class Address(Base): ... __tablename__ = 'addresses' ... id = Column(Integer, primary_key=True) ... email_address = Column(String(50), nullable=False) ... user_id = Column(Integer, ForeignKey('users.id')) ... user = relationship("User", back_populates="addresses") ... . def __repr__(self): ... return "<Address(email_address='%s')>" % self.email_address

Now when we load the user jack (below using get(), which loads by primary key), removing an address from the corresponding addresses collection will result in that Address being deleted:

# load Jack by primary key >>> jack = session.query(User).get(5) # remove one Address (lazy load fires off) >>> del jack.addresses[1] # only one address remains >>> session.query(Address).filter( ... Address.email_address.in_(['[email protected]', '[email protected]']) ... ) .count() 1

Deleting Jack will delete both Jack and the remaining Address associated with the user:

>>> session.delete(jack) >>> session.query(User).filter_by(name='jack').count() 0 >>> session.query(Address).filter( ...  Address.email_address.in_(['[email protected]', '[email protected]']) ... ) .count() 0

Further detail on configuration of cascades is at Cascades. The cascade functionality can also integrate smoothly with the ON DELETE CASCADE functionality of the relational database. See Using Passive Deletes for details.

backref

Setting up two relationships at the same time is too cumbersome. You can use backref instead

from sqlalchemy import Integer, ForeignKey, String, Column
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship

Base = declarative_base()

class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    name = Column(String)

    addresses = relationship("Address", backref="user")

class Address(Base):
    __tablename__ = 'address'
    id = Column(Integer, primary_key=True)
    email = Column(String)
    user_id = Column(Integer, ForeignKey('user.id'))

The above configuration establishes a collection of Address objects on User called User.addresses. It also establishes a .user attribute on Address which will refer to the parent User object.

In fact, the backref keyword is only a common shortcut for placing a second relationship() onto the Address mapping, including the establishment of an event listener on both sides which will mirror attribute operations in both directions. The above configuration is equivalent to:

rom sqlalchemy import Integer, ForeignKey, String, Column
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship

Base = declarative_base()

class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    name = Column(String)

    addresses = relationship("Address", back_populates="user")
        
class Address(Base):
    __tablename__ = 'address'
    id = Column(Integer, primary_key=True)
    email = Column(String)
    user_id = Column(Integer, ForeignKey('user.id'))

    user = relationship("User", back_populates="addresses")

Above, we add a .user relationship to Address explicitly. On both relationships, the back_populates directive tells each relationship about the other one, The Primary Effect of Eye-voyage That They Should Establish “Bidirectional” Behavior Between Each Other Configuration is that the relationship adds event handlers to both attributes which have the behavior of “when an append or set event occurs here, Set ourselves onto the incoming attribute using this particular attribute name “. Start with a User and an Address instance. The .addresses collection is empty, and the .user attribute is None:

>>> u1 = User()
>>> a1 = Address()
>>> u1.addresses
[]
>>> print(a1.user)
None

However, once the Address is appended to the u1.addresses collection, both the collection and the scalar attribute have been populated:

>>> u1.addresses.append(a1)
>>> u1.addresses
[<__main__.Address object at 0x12a6ed0>]
>>> a1.user
<__main__.User object at 0x12a6590>

This behavior of course works in reverse for removal operations as well, as well as for equivalent operations on both sides. Such as when .user is set again to None, the Address object is removed from the reverse collection:

>>> a1.user = None
>>> u1.addresses
[]

The manipulation of the .addresses collection and the .user attribute occurs entirely in Python without any interaction with the SQL database. Without this behavior, the proper state would be apparent on both sides once the data has been flushed to the database, and later reloaded after a commit or expiration operation occurs. The backref/back_populates behavior has the advantage that common bidirectional operations can reflect the correct state without requiring a database round trip.

Remember, when the backref keyword is used on a single relationship, It’s exactly the same as if the above two relationships were created using back_populates on each.

Mysql operation

Verify our results above and become familiar with the structure of the MySQL table we created

The structure of the address table

> SHOW CREATE TABLE addresses; +-----------+----------------+ | Table | Create Table | |-----------+----------------| | addresses | CREATE TABLE `addresses` ( `id` int(11) NOT NULL AUTO_INCREMENT, `email_address` varchar(50) NOT NULL, `user_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `user_id` (`user_id`), CONSTRAINT `addresses_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET = utf8 | + -- -- -- -- -- -- -- -- -- -- - + -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - + 1 row in the set Time: 0.005 s > DESC addresses; +---------------+-------------+--------+-------+-----------+----------------+ | Field | Type | Null | Key | Default | Extra | |---------------+-------------+--------+-------+-----------+----------------| | id | int(11) | NO | PRI | <null>  | auto_increment | | email_address | varchar(50) | NO | | <null> | | | user_id | int(11) | YES | MUL | <null> | | + -- -- -- -- -- -- -- -- -- -- -- -- -- -- - + -- -- -- -- -- -- -- -- -- -- -- -- -- + + -- -- -- -- -- -- -- -- -- -- -- -- -- - + -- -- -- -- -- -- -- -- -- -- - + -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - + 3 rows in the set Time: 0.002 s

The structure of the user table

> SHOW CREATE TABLE users; +---------+----------------+ | Table | Create Table | |---------+----------------| | users | CREATE TABLE `users` ( `id`  int(11) NOT NULL AUTO_INCREMENT, `name` varchar(50) DEFAULT NULL, `fullname` varchar(50) DEFAULT NULL, `password` varchar(50) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 | +---------+----------------+ 1 row in set Time: 0.002s > DESC users; +----------+-------------+--------+-------+-----------+----------------+ | Field | Type | Null | Key | Default | Extra |  |----------+-------------+--------+-------+-----------+----------------| | id | int(11) | NO | PRI | <null> | auto_increment | | name | varchar(50) | YES | | <null> | | | fullname | varchar(50) | YES | | <null> | | | password | varchar(50) | YES | | <null> | | +----------+-------------+--------+-------+-----------+----------------+ 4 rows in set Time: 0.003 s

Detailed data

> SELECT * FROM addresses; +------+-----------------+-----------+ | id | email_address | user_id | |------+-----------------+-----------| | 3 | [email protected] | 5 | | 4 | [email protected] | 5 | +------+-----------------+-----------+ 2 rows in set Time: 0.002s > SELECT * FROM users; +------+--------+----------------+------------+ | id | name | fullname | password | |------+--------+----------------+------------| | 1 | ed | Ed Jones | f8s7ccs | | 2 | wendy | Wendy Williams | foobar | | 3 | mary | Mary Contrary | xxg527 | | 4 | fred | Fred Flinstone | blah | | 5 | jack | Jack Bean | gjffdd | + -- -- -- -- -- - + + -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - + -- -- -- -- -- -- -- -- -- -- -- - + 5 rows in the set Time: 0.003 s

Zhihu Live designed the model

from sqlalchemy import Column, String, Integer, create_engine, SmallInteger
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base

DB_URI = 'sqlite:///user.db'
Base = declarative_base()
engine = create_engine(DB_URI)
Base.metadata.bind = engine
Session = sessionmaker(bind=engine)
session = Session()
class User(Base):
    __tablename__ = 'live_user'
    
    id = Column(Integer, unique=True, primary_key=True, autoincrement=True)
    speaker_id = Column(String(40), index=True, unique=True)
    name = Column(String(40), index=True, nullable=False)
    gender = Column(SmallInteger, default=2)
    headline = Column(String(200))
    avatar_url = Column(String(100), nullable=False)
    bio = Column(String(200))
    description = Column(String())
    
    @classmethod
    def add(cls, **kwargs):
        speaker_id = kwargs.get('speaker_id', None)
        if id is not None:
            r = session.query(cls).filter_by(speaker_id=speaker_id).first()
            if r:
                return r
        try:
            r = cls(**kwargs)
            session.add(r)
            session.commit()
        except:
            session.rollback()
            raise
        else:
            return r
Base.metadata.create_all()

There are two types of interfaces:

  1. https://api.zhihu.com/lives/o… (Not finished)

  2. https://api.zhihu.com/lives/e… (Closed)

ELASTICSEARCH-DSL-PY (ELASTICSEARCH-PY) is a better encapsulation than ELASTICSEARCH-PY (ELASTICSEARCH-PY). DSL also supports a DOC_TYPE class (similar to a Table in a database) to achieve ORM effect. We’ll use it to write the Live model:

from elasticsearch_dsl import DocType, Date, Integer, Text, Float, Boolean
from elasticsearch_dsl.connections import connections
from elasticsearch_dsl.query import SF, Q
from config import SEARCH_FIELDS
from .speaker import User, session

connections.create_connection(hosts=['localhost'])
class Live(DocType): Id = Integer() speaker_id = Integer() feedback_score = Float() # topic_names = Text(analyzer='ik_max_word') # Topic tag name Seats_taken = Integer() # number of attendees subject = Text(analyzer='ik_max_word') # amount = Float() # price (RMB) description = Text(analyzer='ik_max_word') status = Boolean() # public(True)/ended(False) starts_at = Date() outline = SPEAKER_MESSAGE_COUNT = INTEGER () TAG_NAMES = TEXT (ANALYZER =' IK_MAX_WORD ') liked_num = Integer() class Meta: index = 'live' @classmethod def add(cls, **kwargs): id = kwargs.pop('id', None) if id is None: return False live = cls(meta={'id': id}, **kwargs) live.save() return live

It allows us to organize dictionaries in a very maintainable way:

In : from elasticsearch_dsl.query import Q
In : Q('multi_match', subject='python').to_dict()
Out: {'multi_match': {'subject': 'python'}}
In : from elasticsearch import Elasticsearch In : from elasticsearch_dsl import Search, Q In : s = Search(using=client, index='live') In : S = s.q ('match', subject='python').query(~Q('match', description=' quantization ')) In: s.exute () Out: <Response: [< Hit (live/live / 789840559912009728) : {' subject ':' introduction to Python engineers and prestige ', 'feedback_score: 4.5,' stat...} > >]

The above example shows that the Subject dictionary contains Python from the LIVE index (similar to a Database in a Database), but the DESCRIPTION field does not contain a quantified LIVE.