Is post_save signal called for all the mailbox model instances when we click save button in django model admin? Does the post_save signal work continuously in Apache server?When it is executed behind Apache, just when we refresh the page it again saving the same password in next password column as the previous password column.I need to check password history for 5 passwords to not repeat.The post_save code:
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
The way the post_save signal is connected:
post_save.connect(mbox_post_save, sender=Mbox)
CodePudding user response:
To answer your questions:
Post_save will still kick in if you save an object from the /admin section
It should be listening for all saves of a particular object - it should not be kicking off post_save routines for every object of that type. If this is happening to you there is likely something else going wrong, but I can't see it in the code provided here.
To check the existence of previous passwords is fairly simple. However I think you are making a mistake to put all this as a post_save signal. If you do it post_save you will have saved the mailbox password already, a change you will need to reverse if your password history check fails.
This is better put in the clean() function of your form (or validate() function of your API), so you can case an error if there is a history match.
I'd do it something like this:
forms.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()
then in your form.py clean method (or validation method for an 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'))
Now you can keep your post_save just for creating a new password history in the event of mailbox creation.
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