django try exception statement causing IntegrityError: - django

We use paypal on our system to check whether a user has paid before and already has an account.
This morning I received a traceback that basically gave me an integrity error.
IntegrityError: (1062, "Duplicate entry 'user_1234_before' for key 2")
My statemtent looks as follows.
try:
user = User.objects.get(email=ipn_obj.payer_email)
except:
user_slug = ("%s_%s_before") % (ipn_obj.first_name, ipn_obj.last_name)
username = slugify(user_slug)
user = User.objects.create_user(username, ipn_obj.payer_email, 'testpassword')
user.first_name = ipn_obj.first_name
user.last_name = ipn_obj.last_name
user.save()
Thanks in advance.

Never, ever use a blank except statement. What's happening here is an excellent demonstration of why.
You've presumably used that try/except block to catch the User.DoesNotExist exception. However, your code is actually raising a completely different exception. Because you're swallowing it, it's impossible to know which one, but potentially ipn_obj isn't what you think it is and doesn't have a payer_email error, so you're getting AttributeError. Or, possibly, you're getting the User.MultipleObjectReturned exception.
Change your except to except User.DoesNotExist, and then debug your actual problem.

I think you have two user with different payer_mail but same first_name and last_name: username (made up of first and last name) is the same for the two users. Probably username is a unique key on User and gives you the error.
Apart from catching the right exception (User.DoesNotExist), if you want to retain your code, I think you should 'uniquify' the username using the email field (which I suppose is unique):
user_slug = ("%s_%s_before") % (ipn_obj.first_name, ipn_obj.last_name)
with:
user_slug = ("%s_%s_%s_before") % (ipn_obj.first_name, ipn_obj.last_name, ipn_obj.payer_email)
or:
user_slug = ("%s_before") % (ipn_obj.payer_email)

The exception is actually being raised by the creation (ie INSERT statement) of a user with an already took username.
You shall check for its existence before doing this insertion .

Related

Django - How to tertermine content_type in if statement?

I want to find out what content_type I'm about in my function but I'm Unable to reach the "got me" print statement no matter how I design my if statement. I also tried to use pprint to get the naming of the content_type but with no effect till now.
def mark_refunded(modeladmin, request, queryset):
queryset.update(status=2)
transactions = queryset.all()
for transaction in queryset.all():
print(transaction)
transaction.sender.acc_usd_balance += float(transaction.amount)
transaction.sender.save()
transaction.receiver.acc_usd_balance -= float(transaction.amount)
transaction.receiver.save()
print(transaction.content_type)
if transaction.content_type == "App | Sell Type A":
print("got me")
It seems that I'm unable to compare the output of print(transaction.content_type) with the if statement, why that?
I would expect that the output is the same value that I ask for at the if statement.
Assuming content_type is a foreign key, you'd need to compare if str(...) == ....
However, the more important issue here is that multiple concurrent requests will eventually absolutely surely corrupt those account balances since you're not managing them in an atomic way.

What are the differences between using self.add_error() and raising a ValidationError()?

You can throw a validation error in 2 ways. The first is with self.add_error() and the second with raise ValidationError().
I've read that when you use self.add_error('field1','description here') then field1 is also automatically removed from the cleaned_data list and i assume a ValidationError object is also added to the self.errors list, is this correct?
But what happens when you don't choose to use self.add_error and opt for using raise ValidationError instead? Is this object also automatically added to the errors list behind the scenes? And how would you display this error message as caption under the correct invalid field?
Thank you
If you raise an error, the control flow of that method, and callers of that method stops, until there is a method that has span a try-except over that, and catches the exception accordingly.
But sometimes a field might contain multiple errors. For example if you have a password, you might want to add errors because it is too short, does not contain a digit, a lowercase, and/or upppercase.
Then you thus can implement this with:
def clean_password(self):
pwd = self.cleaned_data['password']
if len(pwd) < 10:
self.add_error('password', 'The password is too short.')
if not any(c.isupper() for c in pwd):
self.add_error('password', 'The password should contain an uppercase character.')
if not any(c.islower() for c in pwd):
self.add_error('password', 'The password should contain an lowercase character.')
if not any(c.isdigit() for c in pwd):
self.add_error('password', 'The password should contain an digit.')
return pwd
If you would raise a ValidationError for one of these, it can not add mutliple problems that a password might have.
You can however pass a list of errors to a ValidationError data constructor, hence you can use the two interchangeable.

Cannot obtain user by using filter with username and password

I am using the following code
email = validated_data["login"]
password = validated_data["password"]
user_obj = User.objects.filter(Q(email__exact=email) & Q(password__exact=password))
I changed the password from admin however no user is returned. However if I remove the password check then I get a user object back.The object that I get back if I remove the Q(password__exact=password) condition has _password field as None. This code has been working fine for a while but today it is not returning back the object. Am I missing something here ? I verified that I am receiving the correct username and password from the client.I also tried accessing the admin with that username and password (The account has staff status) and I was able to log in. So the password is correct but for some reason I cant obtain that user by filtering. ? What might I be doing wrong ?
password isn't stored in plain text, but as a hash (and a little more). Get the user by username and check the password:
# assumes there can be only one
user = User.objects.get(email=email)
# this checks the plaintext password against the stored hash
correct = user.check_password(password)
BTW, you don't need Q objects for logical AND. filter(email__exact=email, password__exact=password) would suffice, even though it doesn't make much sense, in this case.
it is because Django doesn't stores password as the simple text they are hashed, you cant perform a password__exact on that it will return none every time unless you are getting the same hash password = validated_data["password"] here

Adding permissions when user is saved in Django Rest Framework

I'm creating an instance of a User object. The creation itself is a standard User.objects.create_user call and that works ok - user is created. After that, I'm trying to add a few permissions to him or her:
for name in ('view_restaurant', 'change_restaurant', 'delete_restaurant',
'view_meal', 'add_meal', 'change_meal', 'delete_meal',
'view_order', 'delete_order',
'view_historicalorder', 'add_historicalorder', 'change_historicalorder',
'view_orderitem',
'view_historicalorderitem',
'view_restaurantemployee', 'add_restaurantemployee', 'change_restaurantemployee', 'delete_restaurantemployee'):
permission = Permission.objects.get(codename=name)
print(permission is None)
user.user_permissions.add(permission)
user.save()
print(user.has_perm(permission))
As you can see, in the last line I'm checking whether the user was assigned with an appropriate permission, and few lines above I'm checking if permission is None. The result is that the permission object is never none, but user.has_perm call always returns false. What am I doing wrong here?
You're calling has_perm incorrectly. It expects a string in this format
"<app label>.<permission codename>"
As an aside, may I recommend to simplify your code like so:
codenames = 'view_restaurant', 'change_restaurant', ...
perms = Permission.objects.filter(codename__in=codenames)
user.user_permissions.add(*perms)

Python while loop does not stop

I am writing a script to ask user to enter a date. If it is a date format, then return the entry; otherwise, continue. But my code doesn't stop even the user input is valid. Could somebody please share some insight? Thanks!
def date_input(prompt):
while True:
date_text = raw_input(prompt)
try:
datetime.datetime.strptime(date_text, '%Y-%m-%d')
return date_text
except:
print('Invalid input.')
continue
You should never use except, always check for a specific exception:
except ValueError:
Then your real error should come through. I suspect you didn't import datetime.