I have a query in which all fields are required. I want to make sure they're full. It turns out a lot of duplicate code. So I decided to create a function to which I pass values from a field. But the request continues rather than sending a response code 400.
My views.py
def pay(request):
body = request.body.decode('utf-8')
if not body:
return JsonResponse({
'status': 'failed',
'errors': {
'code': 400,
'message': 'empty query'
},
})
body = json.loads(body)
phone = body.get('phone')
amount = body.get('amount')
merch_name = body.get('merchant_name')
#check_field(phone)
if not phone:
return JsonResponse({
'status': 'failed',
'errors': {
'code': 400,
'message': 'phone field is empty'
},
})
if not amount:
return JsonResponse({
'status': 'failed',
'errors': {
'code': 400,
'message': 'amount field is empty'
},
})
if not merch_name:
return JsonResponse({
'status': 'failed',
'errors': {
'code': 400,
'message': 'merch_name field is empty'
},
})
My function:
def check_field(field):
if not field:
logger.info('its work')
return JsonResponse({
'status': 'failed',
'errors': {
'code': 400,
'message': '{} field is empty'.format(field)
},
})
How i can fix it?
I think your code is almost right, but it should return a JsonResponse
object if check_field
function call's return value is not None
. (If the function call does not return any value, it actually return None
)
def pay(request):
...
check_result = check_field(phone)
if check_result is not None:
return check_result
... (repeat ...)
Anyway, I suggest you should try Django REST Framework's Serializer . It makes these parameter checking problems easily.
That's because the returned value from the called function ( check_field(phone)
) is not propagated beyond the caller -- the pay
function. It's pay
method's responsibility to take decisions based on the return from check_field
.
You have a couple of options:
keep the earlier long function with a helper function that gets you you the JsonResponse
for the passed field eg:
def get_400_response(field_name): return JsonResponse({ 'status': 'failed', 'errors': { 'code': 400, 'message': f'{field_name} can not be empty' }, })
and from the pay
function eg:
if not phone: return get_400_response('phone') # note the `return` here
if you want to use check_field
, you can either keep it as is and then check from pay
that if the return is a JsonReponse
, if so return, otherwise save it as a valid value:
phone = body.get('phone') if isinstance(phone, JsonResponse): return phone
Another option would be to raise an exception eg ValidationError
from the check_field
function, and rather than doing isinstance
check, handle that in a try
- except
, so essentially duck-typing.
Better approach: it would be a better idea to accumulate all the errors from all fields and send them as a single response, it increases usability. So you can create a function that do the validations solely (leveraging other tiny functions as needed) and send either the validated data or a ValidationError
for invalid data, and you can handle it from pay
.
Note that your check_field
does not work as is, because field
refers to the value not the name of the variable you pass in.
Using exceptions avoids code duplication:
from django.core.exceptions import ValidationError
def pay(request):
try
body = request.body.decode('utf-8')
if not body:
raise ValidationError('empty query')
body = json.loads(body)
for field_name in ['phone', 'amount', 'merchant_name']:
check_field(body, field_name)
except ValidationError as error:
return JsonResponse({
'status': 'failed',
'errors': {
'code': 400,
'message': error.message
},
})
def check_field(data, field_name):
if not data.get(field_name):
raise ValidationError('{} field is empty'.format(field_name)
I second the suggestion of @youngminz to look into Django REST Framework serializers. Alternatively, you can also use a regular Django form.
If amount
is a number and 0 is a valid value, you have to use data.get(field_name) is None
for the check.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.