web-dev-qa-db-fra.com

django: élever BadRequest comme exception?

Est-il possible de lever BadRequest comme exception dans django?

J'ai vu que vous pouvez soulever un 404 [1].

Cas d'utilisation: dans une méthode d'assistance, je charge un JSON à partir de request.GET. Si le json a été coupé depuis que le navigateur (IE) a coupé l’url, je voudrais lever une exception correspondante.

Une exception BadRequest semble appropriée, mais jusqu'à présent, aucune exception de ce type ne semble exister dans Django.

Dans 1.6, il existe une exception SuspiciousOperation. Mais cela ne correspond pas dans mon cas, car ce n’est pas lié à la sécurité.

Bien sûr, je pourrais essayer try..except autour de ma méthode d'assistance dans la méthode view, mais ce n'est pas DRY.

Quelqu'un a-t-il une solution pour laquelle je n'ai pas besoin d'essayer… d'exception pour chaque appel de la méthode d'assistance?

[1] https://docs.djangoproject.com/fr/1.6/ref/exceptions/#Django.core.urlresolvers.Resolver404

Mettre à jour

Exemple de code:

def my_view(request):
    data=load_data_from_request(request) # I don't want a try..except here: DRY
    process_data(data)
    return Django.http.HttpResponse('Thank you')

def load_data_from_request(request):
    try:
        data_raw=json.loads(...)
    except ValueError, exc:
        raise BadRequest(exc)
    ...
    return data
13
guettli

Vous avez besoin d'un middleware personnalisé pour gérer les exceptions que vous montez . Vous devez disposer d'exceptions personnalisées pour le vérifier dans le middleware.

class ErrorHandlingMiddleware(object):
    def process_exception(self, request, exception):
        if not isinstance(exception, errors.ApiException): # here you check if it yours exception
            logger.error('Internal Server Error: %s', request.path,
                exc_info=traceback.format_exc(),
                extra={
                    'request': request
                }
            )
        # if it yours exception, return response with error description
        try:
            return formatters.render_formatted_error(request, exception) # here you return response you need
        except Exception, e:
            return HttpResponseServerError("Error During Error Processing")
11
coldmind

Les autres réponses expliquent comment renvoyer une réponse HTTP avec le statut 400.

Si vous souhaitez vous connecter au traitement des erreurs 400 de Django , vous pouvez générer une exception SuspiciousOperation ou une de ses sous-classes.

Voir les docs ici et ici .

Dans votre exemple, cela ressemblerait à:

from Django.core.exceptions import SuspiciousOperation

def load_data_from_request(request):
    try:
        data_raw = json.loads(...)
    except ValueError:
        raise SuspiciousOperation('Invalid JSON')
    # ...
    return data
16
yprez

Au lieu de la réponse de @ coldmind (conversion des exceptions dans une couche de middleware), vous pouvez placer un décorateur sur votre fonction d'affichage qui fait la même chose. Personnellement, je préfère cela, parce que c'est tout simplement vieux-Python, et que je n'ai pas besoin de me dépoussiérer pour comprendre le fonctionnement du middleware Django.

Vous ne voulez pas que toutes les fonctionnalités de vos vues soient intégrées à la rationalité de la conscience (votre module de vue dépend donc de tous les autres modules de votre projet, ce qui conduit à une architecture "tout dépend de tout le reste"). sait juste à propos de http. Il extrait ce dont vous avez besoin de la demande, les délégués à une autre fonction de «logique métier». La logique métier peut déléguer à d'autres modules (par exemple, un code de base de données ou des interfaces avec d'autres systèmes externes.) Enfin, la valeur renvoyée par votre logique métier est ensuite convertie en une réponse http par la fonction d'affichage.

Mais comment communiquer les erreurs à la fonction de visualisation à partir de la logique métier (ou quoi que cela délègue à)? L'utilisation de valeurs de retour est fastidieuse pour de nombreuses raisons. Par exemple, ces valeurs de retour d'erreur devront être propagées à la vue depuis toute votre base de code. Cela est souvent désordonné, car vous utiliserez déjà les valeurs de retour des fonctions à d’autres fins.

La façon naturelle de gérer cela consiste à utiliser des exceptions, mais la vue Django ne convertira pas, en elle-même, les exceptions non capturées en codes d'état HTTP renvoyés (à l'exception de quelques cas particuliers, comme le dit l'OP).

Alors. J'écris un décorateur à appliquer à mon avis. Le décorateur convertit divers types d'exceptions soulevées en différentes valeurs Django.http.HttpResponseXXX renvoyées. par exemple:

# This might be raised by your business logic or database code, if they get
# called with parameters that turn out to be invalid. The database code needs
# know nothing about http to do this. It might be best to define these exception
# types in a module of their own to prevent cycles, because many modules 
# might need to import them.
class InvalidData(Exception):
    pass

# This decorator is defined in the view module, and it knows to convert
# InvalidData exceptions to http status 400. Add whatever other exception types
# and http return values you need. We end with a 'catch-all' conversion of
# Exception into http 500.
def exceptions_to_http_status(view_func):
    @wraps(view_func)
    def inner(*args, **kwargs):
        try:
            return view_func(*args, **kwargs)
        except InvalidData as e:
            return Django.http.HttpResponseBadRequest(str(e))   
        except Exception as e:
            return Django.http.HttpResponseServerError(str(e))
     return inner

 # Then finally we define our view, using the decorator.

 @exceptions_to_http_status
 def myview(self, request):
     # The view parses what we need out of incoming requests
     data = request.GET['somearg']

     # Here in the middle of your view, delegate to your business logic,
     # which can just raise exceptions if there is an error.
     result = myusecase(data)

     # and finally the view constructs responses
     return HttpResponse(result.summary)

Selon les circonstances, vous constaterez que le même décorateur peut travailler sur plusieurs fonctions, voire toutes, de vos vues.

6
Jonathan Hartley

HttpResponseBadRequest est prêt à être utilisé. Il est mis en œuvre as:

class HttpResponseBadRequest(HttpResponse):
    status_code = 400

Modifié en raison de la mise à jour de la question OP.

Vous pouvez créer votre propre assistant et y encapsuler un bloc try-catch.

def myJsonDec(str):
    try:
        ...
5
dani herrera

Je ne suis pas sûr de ce que vous entendez par élévation de BadRequest comme une exception.

Vous pouvez renvoyer une réponse avec le code d'état de votre choix, en utilisant explicitement la sous-classe appropriée de HttpResponse ou en ajoutant un paramètre status à la réponse normale.

0
Daniel Roseman