2015-03-04 9 views
9

Jeśli mam niektóre wartości (łańcuchowe) z żądania GET lub POST z powiązanymi instancjami Property, jeden z nich to IntegerProperty i jeden TextProperty, czy istnieje sposób przekonwertowania wartości na odpowiednie typy (użytkownika) bez długiego żmudnego łańcucha połączeń isinstance?Prawidłowy sposób konwertowania ciągu znaków na właściwy typ dla właściwości NDB?

szukam do odtworzenia tego rodzaju funkcjonalność (wszystkie walidacji wejścia pominięte dla jasności):

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) 

Na przykład, jeśli istnieje sposób, aby uzyskać klasę int z IntegerProperty a klasa bool od BooleanProperty itd., który wykonałby zadanie.

Interfejs API metadanych ndb tak naprawdę nie rozwiązuje tego w sposób elegancki, o ile widzę; z get_representations_of_kind mogę jednak zmniejszyć liczbę przypadków.

+0

Czuję twój ból ... jedno pytanie, powinieneś znać oczekiwane typy danych z pozycji ** POST **, więc dlaczego nie po prostu uzyskać ** wartości ** zgodnie z oczekiwaniami ** klucze ** i przekonwertować je na odpowiedni typ? – Anzel

+0

@Anzel Nie wiesz, co masz na myśli mówiąc o oczekiwanych typach danych z elementów POST. W definicji modelu mam 45 właściwości kilku różnych typów; w interesie Nie powtarzaj się Nie chciałbym powtarzać mapowania pomiędzy nazwami i typami właściwości w dowolnym miejscu, ale wciąż wiem, czy wartość taka jak "prawda" czy "5" musi być interpretowana jako bool, string lub int . –

+0

Rozumiem, co próbujesz zrobić, ale ponieważ dane, które zamierzasz zamienić na CONVERT są albo w danych GET/POST, możesz zdefiniować funkcję konwersji, aby odwzorować parę klucz/wartość ... – Anzel

Odpowiedz

0

Istnieje pakiet Python o nazwie WTForms, który jest ogromnie przydatny do tego i ogólnie sprawia, że ​​przetwarzanie formularzy jest o wiele przyjemniejsze.

Oto bardzo prosty przykład:

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 

Wywołanie f.validate() automatycznie konwertować dane POST do typu danych określonego przez formę. Więc f.text.data będzie ciągiem, a f.n.data będzie int.

Łagodnie obsługuje także nieprawidłowe dane. Jeśli użytkownik wprowadzi literę dla pola liczby całkowitej, wówczas f.n.data będzie None. Możesz również określić komunikaty o błędach, które można łatwo zintegrować ze swoją stroną internetową.

WTForms zabiera ogromną ilość pracy z przetwarzania formularzy!

2

Możesz użyć dict, aby odwzorować typy zdefiniowane przez użytkownika na typy wbudowane, używając obiektu jako klucza i typu wbudowanego jako wartości.

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)) 

Bo tutaj kluczem jest typ obiektu zamiast isinstance sprawdzić, jeśli więcej niż jeden typy zdefiniowane przez użytkownika mapowania jeden wbudowany typ KeyError pojawią się, jeżeli typ nie jest w dict. Musisz więc jawnie dodać każdy typ zdefiniowany przez użytkownika do przełącznika dict.

F.e.

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

Powyżej dodaliśmy nową TextProperty do switch chociaż TextProperty jest podklasą StringProperty. Jeśli nie chcesz tego zrobić, musimy uzyskać klucz z czeku isinstance.
Oto jak to zrobić;

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)) 
Powiązane problemy