Estoy tratando de crear una API para nuestros usuarios. He decidido usar Django-rest-framework
.
Los usuarios solo necesitan solicitudes GET. Cada solicitud GET debe tener un atributo 'token' para determinar qué datos debemos devolver.
Así que creé una función que intenta obtener el objeto de user
del objeto de request
.
def get_user(request): token = request.GET.get('token') if not token: return HttpResponseForbidden() user = get_object_or_404(User,auth_token=token) return user
Quiero usar esta función en mi opinión:
@api_view(['GET']) def products(request): user = get_user(request) products = user.products.all() serializer = ProductSerializer(products, many=True) return JsonResponse(serializer.data, safe=False)
El problema es que cuando no proporciono el atributo token
, surge:
AttributeError en /api/products/
Valor de excepción: el objeto 'HttpResponseForbidden' no tiene atributo 'productos'
En lugar de una respuesta adecuada.
Puedo hacer:
@api_view(['GET']) def products(request): user_or_response = get_user(request) if user_or_response.__class__ != User: return _or_response products = _or_response.products.all() serializer = ProductSerializer(products, many=True) return JsonResponse(serializer.data, safe=False)
Como puede ver, no devuelve automáticamente una respuesta prohibida, sino que la devuelve como usuario. Puedo devolverlo en la vista de products
, pero tal vez haya una mejor manera de hacerlo con Django-rest-framework
.
¿Qué tengo que hacer? ¿Tienes un mejor enfoque o algún consejo?
Sí, HttpResponseForbidden
se devuelve a su función, no desde la vista.
En esta situación, puede probar el siguiente enfoque
def get_user(request): token = request.GET.get('token') if not token: return False user = get_object_or_404(User,auth_token=token) return user @api_view(['GET']) def products(request): user = get_user(request) if not user: return HttpResponseForbidden() products = user.products.all() serializer = ProductSerializer(products, many=True) return JsonResponse(serializer.data, safe=False)
También puede generar potencialmente la excepción en lugar de devolverla en get_user
y luego manejarla con un try/except
dentro de la vista.
De cualquier manera, es un poco más limpio que comparar .__class__
con User
.
Entonces, en este momento parece que estás confundiendo la diferencia entre tu modelo y tu vista. El modelo es lo que busca datos. Por lo general, no debería devolver el código de respuesta ni manejar la validación con errores.
Sin embargo, el comportamiento de Python es correcto. Está devolviendo un objeto de get_user
y luego le está diciendo que espere una propiedad de productos en el objeto devuelto.
Si yo fuera tú, haría esto:
def get_user(request): token = request.GET.get('token') if not token: return user = get_object_or_404(User,auth_token=token) return user @api_view(['GET']) def products(request): user = get_user(request) if not user: return HttpForbiddenResponse() products = user.products.all() serializer = ProductSerializer(products, many=True) return JsonResponse(serializer.data, safe=False)
NO comprobaría la clase. Esto no solo no encaja muy bien en la filosofía Pythonic, sino que también significa que no puede hacer algo como crear una AdminUser(User)
. Si realmente desea devolver un valor arbitrario de get_user
, entonces haría lo siguiente:
@api_view(['GET']) def products(request): user = get_user(request) if not hasattr(user, 'products'): return HttpForbiddenResponse()
Eso verificará una propiedad definida, que coincida con OOP y un enfoque ligeramente más Pythonic.