Многие ко многим — Запрос объекта ассоциации на основе дополнительного поля ассоциации

#flask #flask-sqlalchemy

#flask #flask-sqlalchemy

Вопрос:

У меня есть отношение объекта ассоциации «многие ко многим». Объект ассоциации имеет дополнительное поле для метки времени. Идея состоит в том, чтобы возвращать связанную связь только в том случае, если временная метка ассоциации находится в пределах определенного временного интервала.

models.py

 from rvt import db
from sqlalchemy_utils import IPAddressType


class ReportAssociation(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    entity_id = db.Column(db.Integer, db.ForeignKey('entity.id'))
    report_id = db.Column(db.Integer, db.ForeignKey('report_map.id'))
    timestamp = db.Column(db.DateTime)
    report_map = db.relationship('ReportMap', back_populates='entities')
    entity = db.relationship('Entity', back_populates='report_maps')
    __table_args__ = (
        db.UniqueConstraint('entity_id', 'report_id', 'timestamp'),
    )

    def __repr__(self):
        return f'ReportAssociation: {self.entity} {self.report_map} - {self.timestamp}'

class Entity(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    ip_address = db.Column(IPAddressType, unique=True, nullable=False)
    hostname = db.Column(db.String(64), index=True, nullable=True)
    region = db.Column(db.String(32), index=True, nullable=True)
    geo = db.Column(db.String(32), index=True, nullable=True)
    city = db.Column(db.String(32), index=True, nullable=True)
    asn = db.Column(db.String(8), index=True, nullable=True)
    subnet_desc = db.Column(db.String(256), index=True, nullable=True)
    report_maps = db.relationship('ReportAssociation', back_populates='entity', lazy="dynamic")
    timestamp = db.Column(db.DateTime)

    def __repr__(self):
        return f'<Entity {self.ip_address}>'

class ReportMap(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    pattern = db.Column(db.String(64), nullable=False, unique=True)
    name = db.Column(db.String(32), nullable=False, unique=True)
    short_name = db.Column(db.String(32), nullable=False, unique=True)
    wiki_url = db.Column(db.String(128), nullable=True, unique=False)
    entities = db.relationship('ReportAssociation', back_populates='report_map', lazy="dynamic")

    def __repr__(self):
        return f'<ReportMap {self.name}>'
  

Проблема, с которой я сталкиваюсь, связана с запросом. Работает следующее.

 >>> e = Entity.query.one()
>>> e
<Entity 101.98.10.156>

>>> for i in e.report_maps.all():
...     print(i.timestamp)
...
2019-04-02 21:15:49.985126
2019-04-02 21:15:59.028121

>>> for i in e.report_maps.filter_by(timestamp='2019-04-02 21:15:59.028121'):
...     print(i.timestamp)
...
2019-04-02 21:15:59.028121
  

Проблема возникает, когда я пытаюсь использовать что-то вроде приведенного ниже

 >>> for i in e.report_maps.filter(timestamp < '2019-04-02 21:15:59.028121'):
...     print(i.timestamp)
...
Traceback (most recent call last):
  File "<console>", line 1, in <module>
NameError: name 'timestamp' is not defined
  

Любая помощь была бы оценена. Спасибо

Ответ №1:

При использовании метода filter вы должны использовать className.attribue, поэтому можете использовать свой последний запрос следующим образом:

 e.report_maps.filter(Entity.timestamp < '2019-04-02 21:15:59.028121').all()