Сигнал Django 3.2 post_save вызывается для всех экземпляров модели, даже если в коде используется 1 экземпляр для сохранения

Вызывается ли сигнал post_save для всех экземпляров модели почтового ящика, когда мы нажимаем кнопку «Сохранить» в администраторе модели django? Работает ли сигнал post_save постоянно на сервере Apache? Когда он выполняется за Apache, просто когда мы обновляем страницу, он снова сохраняет тот же пароль в следующем столбце пароля, что и предыдущий столбец пароля. Мне нужно проверить историю паролей для 5 паролей, чтобы не Repeat. Код post_save:

def check_oldest_password_instance(mbox):
    passwd_list =  []
    oldest_password = None
    oldest_password_datetime = datetime.now()
    pfield = '1'
    n = 0
    mphistory = Phistory.objects.filter(mbox=mbox)
    if mphistory:
        print('======phistory exists====', mphistory)
        for p in mphistory:
            if p.password1:
                passwd_list.append(p.password1)
                oldest_password_datetime = p.datetime1
                oldest_password = p.password1
                pfield = '1'
            if p.password2:
                passwd_list.append(p.password2)
                if oldest_password_datetime > p.datetime2:
                    oldest_password_datetime = p.datetime2
                    oldest_password = p.password2
                    pfield = '2'
            if p.password3:
                passwd_list.append(p.password3)
                if oldest_password_datetime > p.datetime3:
                    oldest_password_datetime = p.datetime3
                    oldest_password = p.password3
                    pfield = '3'
            if p.password4:
                passwd_list.append(p.password4)
                if oldest_password_datetime > p.datetime4:
                    oldest_password_datetime = p.datetime4
                    oldest_password = p.password4
                    pfield = '4'
            if p.password5:
                passwd_list.append(p.password5)
                if oldest_password_datetime > p.datetime5:
                    oldest_password_datetime = p.datetime5
                    oldest_password = p.password5
                    pfield = '5'
        print(len(passwd_list),pfield,'passwd_list_len,pfield_oldest')
        n = len(passwd_list)
        # For new mailbox, check if all 5 values are populated 
        # if n == 0:
        #     pfield = '1'
        if n == 1:
            pfield = '2'
        if n == 2:
            pfield = '3'
        if n == 3:
            pfield = '4'
        if n == 4:
            pfield = '5'
        print(pfield,n, 'pfield-n------------------')
    else:
        oldest_password = None
        n = 0
        pfield = '1'

    return (pfield, passwd_list)


def mbox_post_save(sender, instance, created, **kwargs):
    mphistory = None
    new_phistory = None
    mphistory = None
    print('post save callllll')
    if created:
        # Store the hashed password in Phistory table
        #----------------
        new_phistory = Phistory()
        new_phistory.mbox = instance
        new_phistory.password1 = instance.mpassword
        new_phistory.datetime1 = datetime.now()
        new_phistory.save()
        #----------------
    else:
        print('# edit mbox post_save')

        # Store the hashed password in Phistory table
        #----------------
        try:
            mphistory = Phistory.objects.get(mbox=instance)
            print(mphistory,'mppppp=======================')
        except Exception as e:
            print(e)
        if mphistory:
            print('PHISTORY--------')
            (oldest_pfield, passwd_list) = check_oldest_password_instance(instance)
            if oldest_pfield == '1':
                mphistory.password1 = instance.mpassword
                mphistory.datetime1 = datetime.now()
            elif oldest_pfield == '2':
                mphistory.password2 = instance.mpassword
                mphistory.datetime2 = datetime.now()
            elif oldest_pfield == '3':
                mphistory.password3 = instance.mpassword
                mphistory.datetime3 = datetime.now()
            elif oldest_pfield == '4':
                mphistory.password4 = instance.mpassword
                mphistory.datetime4 = datetime.now()
            elif oldest_pfield == '5':
                mphistory.password5 = instance.mpassword
                mphistory.datetime5 = datetime.now()
            mphistory.save()
        else:
            if not mphistory:
                print('# Add new phistory object 1st time for existing mbox')
                new_phistory = Phistory()
                new_phistory.mbox = instance
                new_phistory.password1 = instance.mpassword
                new_phistory.datetime1 = datetime.now()
                new_phistory.save()
        #----------------

    return

Способ подключения сигнала post_save:

post_save.connect(mbox_post_save, sender=Mbox)

Не понятно в чем проблема и как это воспроизвести. Прочтите Как создать минимальный воспроизводимый пример.

aaron 03.01.2023 06:35
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
109
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Чтобы ответить на ваши вопросы:

Post_save все равно сработает, если вы сохраните объект из раздела /admin

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

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

Это лучше поместить в функцию clean() вашей формы (или validate() функцию вашего API), чтобы вы могли столкнуться с ошибкой, если есть совпадение истории.

Я бы сделал что-то вроде этого:

формы.py

#first some support functions

def get_password_history(mbox):
     #Is there an existing Phistory?
     try:
         mphistory = Phistory.objects.get(mbox=mbox)
     except Phistory.DoesNotExist
         return False
     return mphistory    


def is_password_used(mphistory, password):
    #look for the password in the existing records
    password_list = [
                mphistory.password1, 
                mphistory.password2, 
                mphistory.password3, 
                mphistory.password4, 
                mphistory.password5, 
            ]
    if password in password_list:
         return True
    return False

def update_password_history(mphistory, password):
    #I haven't bothered with datetime here as the oldest is always the highest,
    #but if you need it you can add lines for that field to do a similar swap.
    mphistory.password5  = mphistory.password4 
    mphistory.password4  = mphistory.password3 
    mphistory.password3  = mphistory.password2
    mphistory.password2  = mphistory.password1 
    mphistory.password1  = password
    mphistory.save()

затем в вашем чистом методе form.py (или методе проверки для API)

def clean(self):
    cleaned_data = super().clean()
    history = get_password_history(self)
    if history:
        previous_password_exists = is_password_used(history, cleaned_data.get('mpassword')
        if previous_password_exists:
            raise forms.ValidationError(
                "The password has been used in the last five changes"
            )
        else:
            #the below could also be done in your view after form.is_valid for clarity
            update_password_history(history, cleaned_data.get('mpassword'))
                           

Теперь вы можете сохранить свой post_save только для создания новой истории паролей в случае создания почтового ящика.

def mbox_post_save(sender, instance, created, **kwargs):
    print('post save phistory creation')
    if created:
        # Store the hashed password in Phistory table
        #----------------
        new_phistory = Phistory()
        new_phistory.mbox = instance
        new_phistory.password1 = instance.mpassword
        new_phistory.datetime1 = datetime.now()
        new_phistory.save()
        #----------------

    return

Причина использования всего кода в post_save заключается в том, чтобы, наконец, создать API для вызова в diff. почтовые клиенты. Однако постараюсь использовать более чистый метод и обновить

user956424 06.01.2023 12:14

Вы можете использовать в представлении тот же процесс, что и в методе clean() выше, если ваш API отправляет достаточно информации для идентификации существующего почтового ящика пользователя как части POST. Просто запустите проверку, прежде чем какие-либо изменения будут сохранены в базе данных, и корректно завершите проверку, если совпадение будет найдено.

SamSparx 07.01.2023 23:27

с описанным выше подходом с небольшими исправлениями кода он работает отлично. Теперь нет множественных обновлений mbox при обновлении одного экземпляра через post_save. Спасибо!

user956424 09.01.2023 14:16

Другие вопросы по теме