Django: есть ли способ выполнить последовательные операции model.save () как один запрос к БД? - PullRequest
0 голосов
/ 10 октября 2018

У меня есть функция, которая выполняет операции с экземпляром модели Django, и я пытаюсь разбить ее на подоперации, которые можно использовать независимо.Однако это означает, что я в конечном итоге вызываю .save при каждом изменении и запускаю запрос БД.

def subop1(instance):
    instance.a1 = 1
    instance.save()

def subop1(instance):
    instance.a2 = 2
    instance.save()

def subop1(instance):
    instance.a3 = 3
    instance.save()

def main_op(instance):
    subop1(instance) # triggers 1 DB request
    subop2(instance) # triggers 1 DB request
    subop3(instance) # triggers 1 DB request

Есть ли способ избежать того, чтобы .save каждый раз инициировал запрос к БД, сохраняя при этом каждую функцию независимо работоспособной?Может быть, какой-то способ отложить операции .save до завершения работы какого-либо менеджера контекста и затем сохранить все сразу с 1 запросом БД.

Пытался прочитать документацию transaction, но я не нашел ничего подходящего.

Ответы [ 3 ]

0 голосов
/ 10 октября 2018

Вы можете сделать следующим образом.

def subop1(instance):
instance.a1 = 1

def subop1(instance):
instance.a2 = 2

def subop1(instance):
instance.a3 = 3

def main_op(instance):
subop1(instance)
subop2(instance)
subop3(instance) 
instance.save() 
0 голосов
/ 10 октября 2018

Вы можете добавить необязательный аргумент в ваши методы, например:

def subop1(instance, commit=True):
    instance.a1 = 1
    if commit:
        instance.save()

Затем вызвать ваши экземпляры с помощью commit=False, а затем вызвать save() вручную.

def main_op(instance):
    subop1(instance, commit=False)
    subop2(instance, commit=False)
    subop3(instance, commit=False)
    instance.save()
0 голосов
/ 10 октября 2018

Метод 1:

Экземпляр такой же, поэтому вы можете сделать это:

def subop1(instance):
    instance.a1 = 1

def subop1(instance):
    instance.a2 = 2

def subop1(instance):
    instance.a3 = 3

def main_op(instance):
    subop1(instance)
    subop2(instance)
    subop3(instance) 
    instance.save() # triggers 1 DB request

Вы можете сделать это, потому что экземпляр является объектом, и этопередается по ссылке, а не по значению.

Таким образом, если вы редактируете экземпляр в функции, изменения также остаются вне этого метода

Метод 2:

Или вы можете сделать что-то вроде этого:

from threading import Timer

class Object():
    a1 = 0
    a2 = 0
    a3 = 0

    def save(self):
        print(self.a1)
        print(self.a2)
        print(self.a3)        

def subop1(instance):
    instance.a1 = 1
    restart_timer(instance)

def subop2(instance):
    instance.a2 = 2
    restart_timer(instance)


def subop3(instance):
    instance.a3 = 3
    restart_timer(instance)


def main_op(instance):
    subop1(instance)
    subop2(instance)
    subop3(instance)

timer = None

def restart_timer(instance):
    global timer
    if timer != None:
        timer.cancel() # this delete last timer
    timer = Timer(5.0, Object.save, [instance]) # This call the save method after 5 sec
    timer.start() # This start the new timer

if __name__ == '__main__':
    obj = Object()
    main_op(obj)

Обратите внимание однако, это не лучший способ сделать это, потому что сборщик мусора может устранить экземпляр, поэтому используйте этометод, только если вы уверены, что объект будет оставаться глобальным все время.

В противном случае вы должны добавить этот метод к классу объекта.

def __exit__(self, exc_type, exc_value, traceback):
    self.save()

Обратите внимание, pt.2 В этом случае ваш предмет будет сохранен при каждом его удалении.Поэтому, если вы не сохраните объект добровольно, он все равно будет сохранен.

Таким образом, лучший способ в конечном итоге - выполнить больше транзакций в базе данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...