9
votes

Django champ personnalisé: exécuter uniquement à_python () sur les valeurs de DB?

Comment puis-je vous assurer que la méthode de mon champ personnalisé * TO_PYTHON () * est appelée que lorsque les données du champ ont été chargées à partir de la DB? strong>

J'essaie d'utiliser un Champ personnalisé Pour gérer le codage / décodage de base64 d'une propriété modèle unique. Tout semblait fonctionner correctement jusqu'à ce que j'ai instancié une nouvelle instance du modèle et définir cette propriété avec sa valeur en plainte ... À ce stade, Django a essayé de décoder le champ mais a échoué car il était en clair. P>

L'attrait de l'implémentation sur le terrain sur mesure était que je pensais pouvoir gérer 100% de la logique de codage / décodage là-bas, de sorte qu'aucune autre partie de mon code n'a jamais besoin de savoir à ce sujet. Qu'est-ce que je fais mal? P>

(Remarque: Ceci est juste un exemple pour illustrer mon problème, je n'ai pas besoin de conseils sur la manière dont je devrais ou ne devrait pas utiliser le codage de base64) em > P>

>>> from myapp.models import *
>>> obj = Person(internal_id="foo")
>>> obj.internal_id
'foo'
>>> obj.save()
>>> newObj = Person.objects.get(internal_id="foo")
>>> newObj.internal_id
'foo'
>>> newObj.internal_id = "bar"
>>> newObj.internal_id
'bar'
>>> newObj.save()


0 commentaires

3 Réponses :


0
votes

Obtenez-vous uniquement le typeError code> lorsque vous avez d'abord attribuer une valeur au champ? Vous pouvez simplement écrire un essai / sauf l'enthousiasme:

def to_python(self, value):
  try:
   return decode(value)
  except TypeError:
   return value


3 commentaires

Ouais, cela m'a eu lieu aussi ... J'espérais une solution plus propre. Je suis assez nouveau à Django en général, et plus particulièrement, c'est ma première fois à l'aide d'un champ personnalisé, alors mon hypothèse était que, soit je manque quelque chose dans la déclaration de mon champ personnalisé, ou qu'il y a un tout différent, plus approprié moyen de répondre à mes besoins.


S'avère que c'était en fait la seule solution que je pouvais trouver. Déçu, il n'y a pas de meilleure façon de le faire.


Cela échouera si les données que vous stockez se trouve être une entrée de base64 valide64 (par exemple, B'ABCD '). Ensuite, aucun TypeError est soulevé et le résultat est faux.



4
votes

(de http: //davidcramer.posterous .com / code / 181 / personnalisé-champs-in-django.html
et https: / /docs.djangoproject.com/fr/dev/howto/custom-model-fields/#converting-database-values-a-pytHon-Objects ) em>

Il semble que vous ayez besoin d'être Capable de tester s'il s'agit d'une instance et du problème avec celui-ci est celui-ci est le même type (chaîne de chaîne codée String VS B64), à moins que vous ne puissiez détider la différence que je suggérerais de vous assurer de toujours: P>

Person(internal_id=base64.b64encod("foo"))


2 commentaires

+1 pour la citation des gang-extensions - ce n'est pas seulement limité aux champs Django, le problème peut survenir lors de la rédaction de propriétés avec des descripteurs __ ensemble __ / __ obtenir __ __ ce préfixe Truc peut être hacable mais c'est assez efficace.


+1 Thnx @james Khoury ... Votre suggéré Modifier le code source est très utile pour moi ...



3
votes

J'ai exactement le même problème, mais avec des données JSON. Je veux stocker des données dans la base de données au format JSON. Toutefois, si vous essayez de stocker un objet JSON déjà sérialisé, il sera renvoyé désérialisée. Donc, la question est que ce qui entre, n'est pas toujours ce qui sort. Surtout si vous essayez de mémoriser un numéro comme une chaîne, elle sera renvoyée sous forme d'int ou float, car il est désérialisée par to_python avant d'être stockés.

La solution est simple, mais pas trop élégant. Assurez-vous simplement de stocker le « type » de données ainsi que les données, dans mon cas, ce sont des données JSON, donc je préfixe avec « JSON: »., et donc vous savez toujours si les données proviennent de la base de données

def get_prep_value(self, value):
    if value is not None:
        value = "json:"+json.dumps(value)
    return value
def to_python(self, value):
    if type(value) in (str, unicode) and value.startswith("json:"):
        value = value[5:]
        try:
            return json.loads(value)
        except:
            # If an error was raised, just return the plain value
            return value
    else:
        return value


1 commentaires

Zut! c'est la seule solution que je cherchais. Il se trouve to_python () est endémique dans django code source et il est appelé partout comme un gâchis. Wtf appeler la même fonction dans form-> db et db-> forme? Qui a conçu ce?