J'ai un dict de base comme suit:
sample = {}
sample['title'] = "String"
sample['somedate'] = somedatetimehere
Quand j'essaye de faire, jsonify(sample)
j'obtiens:
TypeError: datetime.datetime(2012, 8, 8, 21, 46, 24, 862000) is not JSON serializable
Que puis-je faire pour que mon exemple de dictionnaire puisse surmonter l'erreur ci-dessus?
Remarque: Bien que cela puisse ne pas être pertinent, les dictionnaires sont générés à partir de la récupération d'enregistrements d' mongodb
où lorsque j'imprime str(sample['somedate'])
, la sortie l'est 2012-08-08 21:46:24.862000
.
Réponses:
Mise à jour pour 2018
La réponse originale correspondait à la façon dont les champs "date" de MongoDB étaient représentés comme suit:
{"$date": 1506816000000}
Si vous voulez une solution générique Python pour la sérialisation
datetime
en json, consultez la réponse de @jjmontes pour une solution rapide qui ne nécessite aucune dépendance.Comme vous utilisez mongoengine (par commentaires) et pymongo est une dépendance, pymongo a des utilitaires intégrés pour aider à la sérialisation json:
http://api.mongodb.org/python/1.10.1/api/bson/json_util.html
Exemple d'utilisation (sérialisation):
Exemple d'utilisation (désérialisation):
Django
Django fournit un
DjangoJSONEncoder
sérialiseur natif qui traite correctement ce type.Voir https://docs.djangoproject.com/en/dev/topics/serialization/#djangojsonencoder
J'ai remarqué une différence entre
DjangoJSONEncoder
et utiliser une coutumedefault
comme celle-ci:Est-ce que Django dépouille un peu des données:
Donc, vous devrez peut-être faire attention à cela dans certains cas.
la source
Django MongoDB
. Avec ce dernier, vous essayez de rester dans l'ORM django pour maintenir l'état agnostique du backend. Mais parfois, vous ne pouvez pas faire ce dont vous avez besoin dans l'abstraction, vous déposez donc un calque. Dans ce cas, son complètement sans rapport avec votre problème car vous utilisez simplement des méthodes utilitaires pour accompagner le format JSON.Mon vidage JSON rapide et sale qui mange des dates et tout:
la source
default
est une fonction appliquée aux objets qui ne sont pas sérialisables. Dans ce cas, c'est le casstr
, il convertit donc tout ce qu'il ne sait pas en chaînes. Ce qui est idéal pour la sérialisation mais pas si bien lors de la désérialisation (d'où le "rapide et sale") car tout ce qui aurait pu être enchaîné sans avertissement, par exemple une fonction ou un tableau numpy.json.dumps({():1,type(None):2},default=str)
relancesTypeError
, ne peut pas avoir de type ou de tuple.En s'appuyant sur d'autres réponses, une solution simple basée sur un sérialiseur spécifique qui convertit
datetime.datetime
etdatetime.date
objecte simplement en chaînes.Comme vu, le code vérifie simplement si l'objet est de classe
datetime.datetime
oudatetime.date
, puis utilise.isoformat()
pour en produire une version sérialisée, selon le format ISO 8601, YYYY-MM-DDTHH: MM: SS (qui est facilement décodé par JavaScript ). Si des représentations sérialisées plus complexes sont recherchées, un autre code pourrait être utilisé à la place de str () (voir d'autres réponses à cette question pour des exemples). Le code finit par lever une exception, pour traiter le cas où il est appelé avec un type non sérialisable.Cette fonction json_serial peut être utilisée comme suit:
Les détails sur le fonctionnement du paramètre par défaut de json.dumps se trouvent dans la section Utilisation de base de la documentation du module json .
la source
01:00:00+01:00
et02:00:00+00:00
qui ne sont pas censés être les mêmes, selon le contexte. Ils se réfèrent bien entendu au même moment, mais le décalage peut être un aspect pertinent de la valeur.Je viens de rencontrer ce problème et ma solution est de sous
json.JSONEncoder
- classer :Dans votre appel, faites quelque chose comme:
json.dumps(yourobj, cls=DateTimeEncoder)
Le.isoformat()
j'ai reçu d'une des réponses ci-dessus.la source
DjangoJSONEncoder
. docs.djangoproject.com/en/dev/topics/serialization/…return super(DateTimeEncoder, self).default(o)
return super().default(o)
Convertir la date en chaîne
la source
oDate = datetime.datetime.strptime(sDate, '%Y-%m-%d %H:%M:%S.%f')
. Formats obtenus à partir de: docs.python.org/2/library/datetime.html.now()
l'heure locale est utilisée, sans l'indiquer. Au moins.utcnow()
devrait être utilisé (puis un +0000 ou Z ajouté)At least .utcnow() should be used
Pas exactement,datetime.now(timezone.utc)
est recommandé, voir l'avertissement dans: docs.python.org/3.8/library/… .Pour ceux qui n'ont pas besoin ou ne veulent pas utiliser la bibliothèque pymongo pour cela .. vous pouvez réaliser facilement la conversion JSON datetime avec ce petit extrait:
Ensuite, utilisez-le comme ceci:
production:
la source
millis=
être mis en retrait à l'intérieur de l'instruction if? Il est également préférable d'utiliser str (obj) pour obtenir le format ISO qui, je pense, est plus courant.datetime.now()
renvoie l'heure locale (comme un objet datetime naïf) mais votre code suppose qu'ilobj
est en UTC s'il n'est pas sensible au fuseau horaire. Utilisezdatetime.utcnow()
plutôt.Voici ma solution:
Ensuite, vous pouvez l'utiliser comme ça:
la source
isinstance(obj, datetime.datetime)
dans TypeError, ajouter plus de types à gérer et terminer avecstr(obj)
ourepr(obj)
. Et tous vos clichés peuvent simplement pointer vers cette classe spécialisée.J'ai une application avec un problème similaire; mon approche était de JSONize la valeur datetime comme une liste de 6 éléments (année, mois, jour, heure, minutes, secondes); vous pouvez aller en microsecondes en tant que liste de 7 éléments, mais je n'avais pas besoin de:
produit:
la source
Ma solution (avec moins de verbosité, je pense):
Utilisez ensuite
jsondumps
au lieu dejson.dumps
. Il imprimera:Si vous le souhaitez, plus tard, vous pouvez ajouter d'autres cas spéciaux à cela avec une simple torsion de la
default
méthode. Exemple:la source
Ce Q se répète maintes et maintes fois - un moyen simple de patcher le module json de telle sorte que la sérialisation prend en charge datetime.
Utilisez la sérialisation json comme vous le faites toujours - cette fois avec datetime étant sérialisé en isoformat.
Résultat: '{"créé": "2015-08-26T14: 21: 31.853855"}'
Voir plus de détails et quelques mises en garde sur: StackOverflow: datetime JSON entre Python et JavaScript
la source
La méthode json.dumps peut accepter un paramètre facultatif appelé default qui devrait être une fonction. Chaque fois que JSON essaie de convertir une valeur, il ne sait pas comment la convertir appellera la fonction que nous lui avons transmise. La fonction recevra l'objet en question et devrait renvoyer la représentation JSON de l'objet.
la source
si vous utilisez python3.7, alors la meilleure solution est d'utiliser
datetime.isoformat()
etdatetime.fromisoformat()
; ils travaillent avec desdatetime
objets à la fois naïfs et conscients :production:
si vous utilisez python3.6 ou inférieur et que vous ne vous souciez que de la valeur de temps (pas du fuseau horaire), vous pouvez utiliser
datetime.timestamp()
et à ladatetime.fromtimestamp()
place;si vous utilisez python3.6 ou inférieur et que vous vous souciez du fuseau horaire, vous pouvez l'obtenir via
datetime.tzinfo
, mais vous devez sérialiser ce champ par vous-même; la façon la plus simple de procéder consiste à ajouter un autre champ_tzinfo
dans l'objet sérialisé;enfin, méfiez-vous des précisions dans tous ces exemples;
la source
Vous devez utiliser
.strftime()
méthode sur.datetime.now()
méthode pour en faire une méthode sérialisable .Voici un exemple:
Production:
la source
Voici une solution simple pour surmonter le problème "datetime not JSON serializable".
Sortie: -> {"date": "2015-12-16T04: 48: 20.024609"}
la source
Vous devez fournir une classe d'encodeur personnalisée avec le
cls
paramètre dejson.dumps
. Pour citer des documents :Cela utilise des nombres complexes comme exemple, mais vous pouvez tout aussi facilement créer une classe pour encoder des dates (sauf que je pense que JSON est un peu flou à propos des dates)
la source
La manière la plus simple de le faire est de remplacer la partie du dict au format datetime par isoformat. Cette valeur sera effectivement une chaîne en isoformat avec laquelle json est d'accord.
la source
En fait, c'est assez simple. Si vous devez souvent sérialiser des dates, utilisez-les comme des chaînes. Vous pouvez facilement les reconvertir en objets datetime si nécessaire.
Si vous devez travailler principalement en tant qu'objets datetime, convertissez-les en chaînes avant de sérialiser.
Comme vous pouvez le voir, la sortie est la même dans les deux cas. Seul le type est différent.
la source
Si vous utilisez le résultat dans une vue, assurez-vous de renvoyer une réponse correcte. Selon l'API, jsonify effectue les opérations suivantes:
Pour imiter ce comportement avec json.dumps, vous devez ajouter quelques lignes de code supplémentaires.
Vous devez également renvoyer un dict pour répliquer entièrement la réponse de jsonify. Ainsi, le fichier entier ressemblera à ceci
la source
pymongo
.Essayez celui-ci avec un exemple pour l'analyser:
la source
Ma solution ...
Ok, maintenant quelques tests.
la source
Voici ma solution complète pour convertir datetime en JSON et vice-versa.
Production
Fichier JSON
Cela m'a permis d'importer et d'exporter des chaînes, des entiers, des flottants et des objets datetime. Cela ne devrait pas être trop difficile à étendre pour d'autres types.
la source
TypeError: 'str' does not support the buffer interface
. C'est à cause du'wb'
mode ouvert, devrait l'être'w'
. Il souffle également dans la désérialisation lorsque nous avons des données similaires à ce jour,'0000891618-05-000338'
mais pas de modèle correspondant.Convertissez le
date
enstring
la source
En général, il existe plusieurs façons de sérialiser les heures de données, comme:
Si vous êtes d'accord avec la dernière façon, le package json_tricks gère les dates, les heures et les heures, y compris les fuseaux horaires.
qui donne:
Donc tout ce que vous devez faire c'est
puis importez depuis
json_tricks
au lieu dejson
.L'avantage de ne pas le stocker comme une seule chaîne, int ou float vient lors du décodage: si vous rencontrez juste une chaîne ou surtout int ou float, vous devez savoir quelque chose sur les données pour savoir s'il s'agit d'un datetime. En tant que dict, vous pouvez stocker des métadonnées afin qu'elles puissent être décodées automatiquement, ce qui est
json_tricks
fait pour vous. Il est également facilement modifiable pour les humains.Avertissement: il est fait par moi. Parce que j'avais le même problème.
la source
J'ai reçu le même message d'erreur lors de l'écriture du décorateur de sérialisation dans une classe avec sqlalchemy. Donc au lieu de:
J'ai simplement emprunté l'idée de jgbarah d'utiliser isoformat () et ajouté la valeur d'origine avec isoformat (), pour qu'elle ressemble maintenant à:
la source
Une solution rapide si vous voulez votre propre formatage
la source
Si vous êtes des deux côtés de la communication, vous pouvez utiliser les fonctions repr () et eval () avec json.
Vous ne devez pas importer datetime comme
depuis eval se plaindra. Ou vous pouvez passer datetime comme paramètre à eval. Dans tous les cas, cela devrait fonctionner.
la source
J'avais rencontré le même problème lors de l'externalisation de l'objet modèle django pour le vider en JSON. Voici comment vous pouvez le résoudre.
la source
Utilisation de l'utilitaire ci-dessus:
la source
Cette bibliothèque superjson peut le faire. Et vous pouvez facilement personnaliser le sérialiseur json pour votre propre objet Python en suivant cette instruction https://superjson.readthedocs.io/index.html#extend .
Le concept général est le suivant:
votre code doit localiser la bonne méthode de sérialisation / désérialisation basée sur l'objet python. Habituellement, le nom de classe complet est un bon identificateur.
Et puis, votre méthode ser / deser devrait être capable de transformer votre objet en un objet sérialisable Json standard, une combinaison de type python générique, dict, list, string, int, float. Et implémentez votre méthode deser à l'envers.
la source
Je ne suis peut-être pas 100% correct, mais c'est le moyen simple de sérialiser
la source