Самый быстрый способ вставить объект, если он не существует с SQLAlchemy

Итак, я довольно новичок в SQLAlchemy.

У меня есть модель, показывающая, которая содержит около 10 000 строк в таблице. Вот класс:

class Showing(Base):
    __tablename__   = "showings"

    id              = Column(Integer, primary_key=True)
    time            = Column(DateTime)
    link            = Column(String)
    film_id         = Column(Integer, ForeignKey('films.id'))
    cinema_id       = Column(Integer, ForeignKey('cinemas.id'))

    def __eq__(self, other):
        if self.time == other.time and self.cinema == other.cinema and self.film == other.film:
            return True
        else:
            return False

Может ли кто-нибудь дать мне некоторое руководство по наиболее быстрому способу вставить новый показ, если он еще не существует. Я думаю, что это немного сложнее, потому что показ только уникален, если время, cinmea и фильм уникальны на показе.

В настоящее время у меня есть этот код:

def AddShowings(self, showing_times, cinema, film):
    all_showings = self.session.query(Showing).options(joinedload(Showing.cinema), joinedload(Showing.film)).all()
    for showing_time in showing_times:
        tmp_showing = Showing(time=showing_time[0], film=film, cinema=cinema, link=showing_time[1])
        if tmp_showing not in all_showings:
            self.session.add(tmp_showing)
            self.session.commit()
            all_showings.append(tmp_showing)

который работает, но кажется очень медленным. Любая помощь очень ценится.

Ответ 1

Если какой-либо такой объект уникален на основе комбинации столбцов, вы должны пометить их как составной первичный ключ. Добавьте параметр ключевого слова primary_key=True в каждый из этих столбцов, полностью отбросив столбец id:

class Showing(Base):
    __tablename__   = "showings"

    time            = Column(DateTime, primary_key=True)
    link            = Column(String)
    film_id         = Column(Integer, ForeignKey('films.id'), primary_key=True)
    cinema_id       = Column(Integer, ForeignKey('cinemas.id'), primary_key=True)

Таким образом, ваша база данных может более эффективно обрабатывать эти строки (нет необходимости в увеличивающемся столбце), и SQLAlchemy теперь автоматически узнает, что два экземпляра Showing - это одно и то же.

Я считаю, что вы можете просто объединить свой новый Showing обратно в сеанс:

def AddShowings(self, showing_times, cinema, film):
    for showing_time in showing_times:
        self.session.merge(
            Showing(time=showing_time[0], link=showing_time[1],
                    film=film, cinema=cinema)
        )