Come gestire il pattern Django get-single-instance-in-view?

3

Molte delle mie viste su Django iniziano un po 'in questo modo:

try:
    # here request.POST could also be request.GET or a captured URL parameter
    MyModel.objects.get(user = request.user, some_attr = int(request.POST['some_val']))
except KeyError:
    # error_view is a view that returns a pretty, formatted 500 response
    return error_view(request, message = 'Incomplete data was submitted (some_val was missing). No action was taken.', next = request.get_full_path())
except ValueError:
    return error_view(request, message = 'The data (some_val = %s) was not formatted correctly. No action was taken.' % request.POST['some_val'], next = request.get_full_path())
except MyModel.DoesNotExist:
    return error_view(request, message = 'The data you were looking for (some_val = %s) could not be found. It is possible you used an outdated form, or the data was just recently removed. No action was taken.' % request.POST['some_val'], next = request.get_full_path())

Mi trovo a ripetere un codice molto simile a questo (ma con diversi POST / GET / url, argomenti del filtro, tipo di dati, url o messaggi successivi), a volte diversi per una vista.

Qual è il modo migliore per avvicinarsi a questo?

  1. Continua a ripetere queste 8 righe, il codice è abbastanza diverso da non violare DRY
  2. Crea un decoratore che passa l'istanza alla vista o restituisce la visualizzazione dell'errore. Cambia la firma della funzione (ok?) E non così facile da generalizzare.
  3. Scrivi una funzione per farlo. In tal caso, dovrebbe ...
    1. ... restituisce una risposta o un'istanza, restituiscila se è una risposta.
    2. ... restituisce una tupla (istanza, risposta), oneo che è None, risintonizzando la risposta se non è None.
    3. ... genera un tipo speciale di eccezione (ad esempio VisibleException) e crea un middleware per visualizzarlo utilizzando error_view .
  4. ... qualcos'altro?

Tutti i metodi funzionano, ma quale consiglio e perché?

Mi è venuto in mente 3.3 proprio ora e per me ha senso - queste situazioni sono vie di uscita anormali dopo tutto - ma non penso di averlo mai visto prima (devo ammettere che non so cosa cercare per), quindi forse ha un problema. (Il programmatore che usa l'app deve aggiungere un middleware, questo è uno).

EDIT : mi è stato ricordato che get_object_or_404 genera un'eccezione che è visualizzata all'utente, quindi forse 3.3 è un'estensione logica.

    
posta Mark 14.03.2015 - 19:09
fonte

1 risposta

1

Come hai sottolineato, spesso le specifiche di ciò che costituisce i parametri di richiesta non validi sono abbastanza diverse per ogni vista, e quindi includere questo tipo di codice in ogni vista è (credo) bene e non una violazione DRY. Inoltre, si autocorreggono la vista con il codice all'inizio che chiarisce ciò che la vista si aspetta di ricevere, nell'URL, GET o POST, e questo vale qualcosa.

Tuttavia, poiché ci sono alcune situazioni in cui pattern molto specifici potrebbero trarre beneficio dal refactoring, vorrei rimandare al codice Django stesso per una buona guida su quando un decoratore (la tua opzione # 2) o una funzione (opzione # 3) potrebbe essere l'opzione migliore:

  • Django utilizza i decoratori di viste per modelli come la convalida dell'accesso, la convalida dei permessi, ecc. Si noti che queste sono situazioni in cui il decoratore non deve passare i risultati dalla sua elaborazione alla vista stessa .

  • Django fornisce funzioni (piuttosto che decoratori) per gestire situazioni come get_object_or_404 , get_list_or_404 , ecc. Si noti che in queste situazioni, la vista richiede l'accesso ai risultati di l'elaborazione (vale a dire, l'istanza). Queste funzioni sono implementate in modo simile alla tua opzione # 3.3 (anche se penso che anche la versione 3.1 funzionerebbe allo stesso modo).

Per riassumere, l'opzione # 1 di solito è utile e molto utile per il codice di auto-documentazione, ma per modelli molto specifici, determina se la vista ha bisogno di accedere ai risultati. Se è così, l'opzione # 3 è probabilmente migliore (altrimenti, opzione # 2). Se vai con l'opzione # 3, allora 3.3 è il percorso che fa Django, anche se 3.1 sembra ugualmente lavorabile.

Nota a margine:

Hai detto che stai attualmente restituendo una risposta 500 in queste situazioni. Una risposta 500 indica che il server ha riscontrato un errore, che non è il caso qui, e quindi è un codice di risposta errato da consegnare.

Effettua invece una delle seguenti operazioni:

  • Se la tua vista ha un parametro URL acquisito che non è corretto, deve essere restituito un 404 (poiché tale URL non esiste), oppure la visualizzazione dovrebbe restituire un reindirizzamento 301 o 302 su un buon URL.

  • Se la vista ha ricevuto parametri GET o POST che non sono corretti, deve essere restituita una risposta 400 Richiesta errata.

risposta data 20.04.2015 - 12:52
fonte

Leggi altre domande sui tag