2015-03-04 16 views
9

Se ho alcuni valori (stringa) da una richiesta GET o POST con le istanze Property associate, uno IntegerProperty e uno TextProperty, ad esempio, esiste un modo per convertire i valori nei tipi appropriati (utente) senza una lunga catena noiosa delle chiamate isinstance?Modo corretto per convertire una stringa nel tipo corretto per una proprietà NDB?

Sto cercando di riprodurre questo tipo di funzionalità (tutto convalida dell'input omesso per chiarezza):

for key, value in self.request.POST.iteritems(): 
    prop = MyModel._properties[key] 

    if isinstance(prop, ndb.IntegerProperty): 
     value = int(value) 
    elif isinstance(prop, (ndb.TextProperty, ndb.StringProperty)): 
     pass # it's already the right type 
    elif ... 
    else 
     raise RuntimeError("I don't know how to deal with this property: {}" 
          .format(prop)) 

    setattr(mymodelinstance, key, value) 

Per esempio, se c'è un modo per ottenere la classe int da un IntegerProperty e la classe bool da un BooleanProperty ecc., farebbe il lavoro.

L'API di metadati ndb in realtà non risolve in modo elegante, per quanto posso vedere; con get_representations_of_kind posso tuttavia ridurre il numero di casi.

+0

Posso sentire il tuo dolore ... una domanda però, avresti dovuto conoscere i tipi di dati previsti dagli articoli ** POST **, quindi perché non ottenere solo i ** valori ** previsti ** le chiavi ** e le converti nel tipo appropriato? – Anzel

+0

@Anzel Non sei sicuro di cosa intendi con la conoscenza dei tipi di dati previsti dagli articoli POST. Nella definizione del modello ho 45 proprietà di alcuni tipi diversi; nell'interesse di Non ripetere se stessi Mi piacerebbe non ripetere la mappatura tra i nomi di proprietà e tipi ovunque, ma so ancora se un valore come "Vero" o "5" deve essere interpretato come un bool, una stringa o un int . –

+0

Capisco cosa stai cercando di fare, ma dato che i dati che stai per CONVERT sono nei dati GET/POST, puoi definire una funzione di conversione per mappare la coppia chiave/valore ... – Anzel

risposta

0

C'è un pacchetto Python chiamato WTForms che è estremamente utile per questo, e generalmente rende l'elaborazione dei moduli un'esperienza molto più piacevole.

Ecco un esempio molto semplice:

class MyForm(wt.Form): 
    text = MyTextAreaField("Enter text") 
    n = wt.IntegerField("A number") 

f = MyForm(self.request.POST) 
f.validate() 
print f.text.data 
print f.n.data 

Calling f.validate() convertirà automaticamente i dati POST al tipo di dati specificato dal modulo. Quindi f.text.data sarà una stringa e f.n.data sarà un int.

Gestisce inoltre correttamente i dati non validi. Se un utente immette una lettera per il campo intero, allora f.n.data sarà None. Puoi anche specificare i messaggi di errore che possono essere facilmente incorporati nella tua pagina web.

WTForms prende un'enorme quantità di lavoro ingrato dall'elaborazione dei moduli!

2

È possibile utilizzare un dict per eseguire la mappatura tra tipi definiti dall'utente su tipi predefiniti utilizzando type dell'oggetto come chiave e un tipo predefinito come valore.

F.e.

class IntegerProperty(int): 
    pass 

class StringProperty(str): 
    pass 

a, b = IntegerProperty('1'), StringProperty('string') 

def to_primitive(obj): 
    switch = {IntegerProperty: int, StringProperty: str} 
    return switch[type(obj)](obj) 

for x in (a, b): 
     print(to_primitive(x)) 

Perché qui la chiave è tipo dell'oggetto anziché isinstance controllo, se più di una tipi definiti dall'utente mappano un singolo tipo incorporato KeyError sorgerà se il tipo non è nella dict. Quindi devi aggiungere esplicitamente ogni tipo definito dall'utente allo switch dict.

F.e.

class TextProperty(StringProperty): 
    pass 
switch = {IntegerProperty: int, StringProperty: str, TextProperty: str} 

Sopra abbiamo aggiunto la nuova TextProperty al switch anche se TextProperty è sottoclasse di StringProperty. Se non si desidera farlo, è necessario ottenere la chiave dal controllo isinstance.
Ecco come farlo;

class IntegerProperty(int): 
    pass 

class StringProperty(str): 
    pass 

class TextProperty(StringProperty): 
    pass 

a, b, c = IntegerProperty('1'), StringProperty('string'), TextProperty('text') 

def to_primitive(obj): 
    switch = {IntegerProperty: int, StringProperty: str} 
    key = filter(lambda cls: isinstance(obj, cls), switch.keys()) 
    if not key: 
     raise TypeError('Unknown type: {}'.format(repr(obj))) 
    key = key[0] 

    return switch[key](obj) 

for x in (a, b, c): 
     print(to_primitive(x)) 
Problemi correlati