Need some help with the if statements and Vaidation errors.
Right now I have this function:
def validate(self, validated_data):
if self.partial:
validated_data = self.fill_data(self.instance, validated_data)
if not validated_data['brand'].sunny_account.first():
raise ValidationError('This brand not Sunny')
validated_data['calculate'] = Account.NEW
return validated_data
Need to add another if statement:
if not validated_data['brand'].moon_account.first():
raise ValidationError('This brand not Moon')
If I add another if not statement in this function it's not going to the second one if not and raising the first Validation error.
I would like that this function checking all if's and raising Validation error for the each case.
From what I understand, you want both the Moon and Sunny errors to be raised. However, this cannot happen: if the first is raised, then the second will never be reached. If the first is not raised, only then can the second be raised. But both can't be raised at the same time.
One solution, do it in a loop:
def validate(self, validated_data):
if self.partial:
validated_data = self.fill_data(self.instance, validated_data)
validations = [
(
validated_data['brand'].sunny_account.first(),
'This brand does not have Sunny enabled'
),
(
validated_data['brand'].moon_account.first(),
'This brand does not have Moon enabled'
),
]
# Validate
err_msg = ""
for cond, msg in validations:
if not cond:
# Has error, add the error message
err_msg = err_msg + msg
if err_msg:
# Error message is not empty --> there is an error
raise ValidationError(err_msg)
validated_data['calculate'] = Account.NEW
return validated_data
It is unusual to want to do this, and handling your exceptions elsewhere might be tricky, but you could raise an Exception of Exceptions something like this:
def my_test(thing):
errors = []
if thing != 1:
errors.append(ValidationError('thing 1'))
if thing != 2:
errors.append(ValidationError('thing 2'))
if errors:
Raise(ValidationError(errors))
You can't raise two exceptions at once, but you can define your own Exception subclass that incorporates arbitrary data. For example, you could store a list of multiple error messages:
class ValidationError(Exception):
def __init__(self):
super().__init__()
self._why: list[str] = []
def __bool__(self) -> bool:
return bool(self._why)
def __str__(self) -> str:
return "\n".join(self._why)
def add(self, why: str) -> None:
self._why.append(why)
and then accumulate multiple messages before deciding to raise:
err = ValidationError()
if not validated_data['brand'].sunny_account.first():
err.add('This brand does not have Sunny enabled')
if not validated_data['brand'].moon_account.first():
err.add('This brand does not have Moon enabled')
if err:
raise err
Related
I have no idea to implement to handle the class variable exception. I am trying to create python module which has dependency with mongodb.
class HrmLookUps(DBMixin):
db_handle = DBMixin.get_db_handle(DBMixin, MONGO_STORE_DICT.get("DB_NAME"),
MONGO_STORE_DICT.get("DB_HOST"),
MONGO_STORE_DICT.get("DB_PORT"),
MONGO_STORE_DICT.get("USERNAME"),
MONGO_STORE_DICT.get("PASSWORD"))
#classmethod
def get_gender(cls):
collection_name = COLLECTION_NAME_DICT.get("COLLECTION_GENDER")
# collection_name = "departments"
gender_record = cls.get_from_db(cls, cls.db_handle, collection_name)
if gender_record[collection_name]:
return gender_record
else:
raise KeyError("Collection Name Invalid!")
I have multiple get method like above get_gender(). I am handling each method raised Keyerror if its data empty.
My question is,
Is this proper way to handle exception of methods?
If my class variable has some issues ex.database credential wrong how can I handle that?
Currently your else clause isn't really doing anything. Your if statement would already throw an error if collection_name wasn't a key in gender_record. So unless you want to raise KeyError in the else clause when collection_name is in gender_record but its value happens to be 0 or False or None.
I think what you are trying to do is something closer to these examples:
#classmethod
def get_gender(cls):
collection_name = COLLECTION_NAME_DICT.get("COLLECTION_GENDER")
# collection_name = "departments"
gender_record = cls.get_from_db(cls, cls.db_handle, collection_name)
if collection_name in gender_record:
return gender_record
else:
raise KeyError("Collection Name Invalid!")
or this maybe
#classmethod
def get_gender(cls):
collection_name = COLLECTION_NAME_DICT.get("COLLECTION_GENDER")
# collection_name = "departments"
gender_record = cls.get_from_db(cls, cls.db_handle, collection_name)
try:
gender_record[collection_name]
return gender_record
else KeyError as err:
raise KeyError("Collection Name Invalid!") from err
Handling exceptions is pretty much the same in any situation. so for the credentials it would be something like this:
try:
db_handle = DBMixin.get_db_handle(DBMixin, MONGO_STORE_DICT.get("DB_NAME"),
MONGO_STORE_DICT.get("DB_HOST"),
MONGO_STORE_DICT.get("DB_PORT"),
MONGO_STORE_DICT.get("USERNAME"),
MONGO_STORE_DICT.get("PASSWORD"))
except <SomeCredentialErrorHere>:
# whatever you put here is what gets executed if the error is raised.
I'm writing a challenge in Python and I would like to know what is the right approach to return None case my function throws an Exception.
def get(email):
try:
customer = get_customer(email)
return customer
except TypeError as e:
logging.error(f'Customer {email} not found', e)
Should I do something like customer = None and return customer after except block?
I wrote a code to catch my error message using try and except (I want to write it without using isinstance) and I am getting the error message when the input is not an integer. The problem is, the program is giving me error message even if the input is valid integer. Please give me some suggestions to make it run. My code is given below:
I tried using exception clause but that did not work.
class Hotel:
def __init__(self,room,catagory):
if room != int:
raise TypeError ()
self.room = room
self.catagory = catagory
self.catagories = {"A":"Elite","B":"Economy","C":"Regular"}
self.rooms = ["0","1","2","3","4","5"]
def getRoom(self):
return self.room
def getCatagory(self):
return self.catagory
return self.catagories.get(self.catagory)
def __str__(self):
return "%s and %s"%(self.rooms[self.room],self.catagories.get(self.catagory))
try:
room1 = Hotel(a,"A")
room2 = Hotel(1,"A")
print(room1.getRoom())
except:
print("there's an error")
I am expecting:
there's an error
1 and Elite
A
You are checking if room != int . It will give you error always.
You have to check type(room)!= int .
I have corrected the code below
class Hotel:
def __init__(self,room,catagory):
if type(room) != int:
raise TypeError ()
self.room = room
self.catagory = catagory
self.catagories = {"A":"Elite","B":"Economy","C":"Regular"}
self.rooms = ["0","1","2","3","4","5"]
Hi I'm pretty new to Python and I've just started to learn about errors and exceptions.I have this function in a class that inserts a line at a given index called num.I know python will raise an error if no num is given but I want to raise my own error.How do I do that?This is what I tried. But the error raised is still the default error?
def insertNum(self, num, line):
if num== None:
raise Exception("Num not specified.")
else:
self.list.insert(num, line)
return self.list
You can use try...except statement.
def insertNum(num, line):
try:
list.insert(num, line)
return list
except:
print('custom error')
You can set the default value of num to None and then check if the value is None.
def insertNum(self, line, num=None):
if num is None:
raise Exception("Num not specified.")
else:
self.list.insert(num, line)
return self.list
If you pass only one parameter to the insertNum method, num will be set the None (the default value) and will raise the exception.
If you don't want to change the order of the arguments, you can use this:
def insertNum(self, num, line=None):
if line is None:
raise Exception("Num not specified.")
else:
self.list.insert(num, line)
return self.list
A simple demonstration for how default arguments work:
>>> def foo(bar, baz=None):
... print(bar, baz)
...
>>> foo(1, 2)
1 2
>>> foo(2)
2 None
I suggest you read about exceptions and errors
But the main idea is that you catch errors and then you handle them the way you like.
try:
#do something
except Exception as e:
# error occured
print("A wild error appeared")
wrap your function with another function that will have try and except` and there you could raise what ever error/exception you want.
def wrapper_func(self, num, line):
try:
self.insertNum(num, line)
except Exception as e:
raise Exception("whatever you want")
def clean(self):
cleaned_data = self.cleaned_data
current_pass = cleaned_data['current_pass']
new_pass = cleaned_data['new_pass']
new_pass2 = cleaned_data['new_pass2']
if current_pass or new_pass or new_pass2:
if not current_pass:
raise forms.ValidationError("- You must enter your current password.")
if not new_pass:
raise forms.ValidationError("- You must enter a new password.")
if not new_pass2:
raise forms.ValidationError("- You must re-confirm your new password.")
return cleaned_data
Right now, I raise my errors. But this means that the other errors won't pop up. it ends the function when I raise the first one. What if I want to have all 3 errors?
A solution could be to bind those errors to the relevant fields, as explained in the docs.
Your code would look like this:
def clean(self):
cleaned_data = self.cleaned_data
current_pass = cleaned_data['current_pass']
new_pass = cleaned_data['new_pass']
new_pass2 = cleaned_data['new_pass2']
if current_pass or new_pass or new_pass2:
if not current_pass:
self._errors["current_pass"] = self.error_class(["- You must enter your current password."])
if not new_pass:
self._errors["new_pass"] = self.error_class(["- You must enter a new password."])
if not new_pass2:
self._errors["new_pass2"] = self.error_class(["- You must re-confirm your new password."])
del cleaned_data["current_pass"]
del cleaned_data["new_pass"]
del cleaned_data["new_pass2"]
return cleaned_data
Please beware that I could not test it personally though.
By using the clean method, you are doing per-form validation. The validator for the whole form has failed.
For individual fields, you should be using the clean_fieldname methods instead of clean which runs after individual field validation.
If you use the clean_fieldname, you can access the errors in forminstance.errors or forminstance.field.errors
def clean_current_pass(self):
data = self.cleaned_data.get('current_pass'):
if not data:
raise forms.ValidationError('- You must enter your current password.')
return data
def clean_new_pass(self):
data = self.cleaned_data.get('new_pass'):
if not data:
raise forms.ValidationError("- You must enter a new password.")
return data
def clean_new_pass2(self):
data = self.cleaned_data.get('new_pass2'):
if not data:
raise forms.ValidationError('- You must re-confirm your new password.')
return data
{{ myform.errors }} would give you all errors in your template.
(This is a Python question not a Django question.)
This is as it should be: when an error is raised it should immediately propagate upwards until it's handled. You can't expect the rest of the function to be evaluated, because the error hasn't been dealt with yet!
Probably the easiest and cleanest method is to rewrite the code:
check = (current_pass, new_pass, new_pass2)
code = ("You must enter your current password.", ...)
err = ''.join(code for i, code in enumerate(codes) if check[i])
if err:
raise forms.ValidationError(err)