Вызывается ли сигнал 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)
Чтобы ответить на ваши вопросы:
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. почтовые клиенты. Однако постараюсь использовать более чистый метод и обновить
Вы можете использовать в представлении тот же процесс, что и в методе clean() выше, если ваш API отправляет достаточно информации для идентификации существующего почтового ящика пользователя как части POST. Просто запустите проверку, прежде чем какие-либо изменения будут сохранены в базе данных, и корректно завершите проверку, если совпадение будет найдено.
с описанным выше подходом с небольшими исправлениями кода он работает отлично. Теперь нет множественных обновлений mbox при обновлении одного экземпляра через post_save. Спасибо!
Не понятно в чем проблема и как это воспроизвести. Прочтите Как создать минимальный воспроизводимый пример.