Sérialisation D'objets clés étrangers à Django

j'ai travaillé sur le développement de certains services RESTful à Django pour être utilisé avec des applications Flash et Android.

le développement de l'interface de services a été assez simple, mais j'ai été confronté à un problème avec la sérialisation des objets qui ont des clés étrangères et beaucoup de relations à plusieurs.

j'ai un modèle comme ceci:

class Artifact( models.Model ):
    name                = models.CharField( max_length = 255 )
    year_of_origin      = models.IntegerField( max_length = 4, blank = True, null = True )
    object_type         = models.ForeignKey( ObjectType, blank = True, null = True )
    individual          = models.ForeignKey( Individual, blank = True, null = True )
    notes               = models.TextField( blank = True, null = True )

alors j'effectuerais une requête sur ce modèle comme ceci, en utilisant select_related(), pour être sûr que les relations étrangères clés sont suivi:

artifact = Artifact.objects.select_related().get(pk=pk)

une Fois que j'ai l'objet, je le sérialiser et passer de retour à ma vue:

serializers.serialize( "json", [ artifact ] )

c'est Ce que j'obtiens en retour, notez que les clés étrangères (object_type et individuels) sont juste l'id de leurs objets connexes.

[
      {
            pk: 1
            model: "artifacts.artifact"
            fields: {
                year_of_origin: 2010
                name: "Dummy Title"
                notes: ""
                object_type: 1
                individual: 1
            }
      }
]

C'est bien beau, mais ce que j'espérais lors de l'utilisation de select_related() était qu'il remplirait automatiquement les champs de clés étrangères avec l'objet correspondant, et pas seulement l'id de l'objet.

je suis récent convertissez-vous en Django, mais mettez un certain temps à développer avec CakePHP.

ce que j'aime vraiment à propos de L'ormeau de gâteau était qu'il suivrait les relations et créerait des objets imbriqués par défaut, avec la capacité de délier les relations quand vous appeliez votre requête.

il était donc très facile de faire abstraction des services d'une manière qui ne nécessitait aucune intervention au cas par cas.

je vois que Django ne fait pas cela par défaut, mais est-il un moyen pour sérialiser un objet et tous les objets associés? Des conseils ou la lecture serait très apprécié.

34
demandé sur Kevin Guan 2010-09-20 20:16:04

4 réponses

j'avais une exigence similaire, mais pas pour des raisons reposantes. J'ai pu obtenir ce dont j'avais besoin en utilisant un module de sérialisation "complet", dans mon cas Django Full Serializers. Cela fait partie de wadofstuff et est distribué sous la nouvelle licence BSD.

Wadofstuff rend cela assez facile. Pour par exemple, dans le cas où vous auriez besoin de faire ce qui suit:

d'abord, installez wadofstuff.

ensuite, ajoutez le paramètre suivant à votre settings.py fichier:

SERIALIZATION_MODULES = {
    'json': 'wadofstuff.django.serializers.json'
}

Troisièmement, faire une légère modification du code utilisé pour la sérialisation:

artifact = Artifact.objects.select_related().get(pk=pk)
serializers.serialize( "json", [ artifact ], indent = 4, 
    relations = ('object_type', 'individual',))

Le principal changement est l' relations mot clé de paramètre. La seule (petite) gotcha est d'utiliser le nom des champs formant la relation pas les noms des modèles.

Avertissement

documentation:

le tas de choses serialiseurs sont 100% compatibles avec le Django sérialiseurs lors de la sérialisation d'un modèle. lors de la désérialisation d'un flux de données le Deserializer la classe ne fonctionne actuellement qu'avec des données sérialisées retournées par les sérialiseurs standards de Django.

(non souligné dans l'original)

J'espère que cela vous aidera.

25
répondu Manoj Govindan 2010-09-20 17:14:19

mise à jour: En fait, la solution de Manoj est un peu dépassée, Wad of Stuff's serializer a été laissé sans mise à jour pendant un certain temps et quand j'ai essayé cela, il semble qu'il ne supporte plus Django 1.6.

Toutefois, prendre un coup d'oeil à le doc officiel de Django ici. Il fournit une certaine façon autour de l'utilisation de la clé naturelle intégrée. Il semble que le serializer intégré de django ait un petit problème de support en utilisant ImageField comme partie de la clé naturelle. Mais qui peut être facilement fixé par votre auto.

10
répondu Shen Haocheng 2016-10-23 14:25:22

Vous pouvez trouver plus d'informations sur ce billet:

autoriser la sérialisation en profondeur en spécifiant la profondeur à suivre la relation https://code.djangoproject.com/ticket/4656

0
répondu guettli 2011-06-27 14:36:33

ajouter une réponse plus récente à cette question plus ancienne: j'ai créé et publié récemment django-serialisable-model comme moyen facilement extensible de sérialiser les modèles, les managers et les jeux de questions. Quand vos modèles s'étendent SerializableModel, ils reçoivent un substituables .serialize méthode qui a un support intégré pour toutes les relations.

à l'Aide de votre exemple, une fois tous les modèles étendre SerializableModel:

joins = ['object_type', 'individual']
artifact = Artifact.objects.select_related(*joins).get(pk=pk)
artifact.serialize(*joins)

appel .serialize avec le les relations en tant qu'arguments feront que la bibliothèque rejaillira sur les objets liés, en appelant .serialize sur eux. Cela renvoie d'un dictionnaire qui ressemble à:

{
  'id': 1,
  'year_of_origin': 2010,
  'name': 'Dummy Title',
  'notes': '',
  'object_type_id': 1,
  'individual_id': 1,
  'object_type': { ... nested object here ... },
  'individual': { ... nested object here ... }
}

vous pouvez alors appeler json.dumps sur ce dictionnaire pour le transformer en JSON.

Par défaut, l'extension SerializableModel définira également le gestionnaire du modèle à SerializableManager (vous pouvez l'étendre vous-même si vous utilisez un gestionnaire personnalisé) qui utilise SerializableQuerySet. Cela signifie que vous pouvez appeler .serialize sur un manager ou d'un queryset comme bien:

artifacts = Artifact.objects.select_related(*joins).all()
artifacts.serialize(*joins)

il s'appelle tout simplement .serialize sur chaque objet model dans le queryset, retour d'une liste de dictionnaires dans le même format que ci-dessus.

django-serialisable-model vous permet également de modifier facilement le comportement par défaut sur la base de chaque modèle, vous donnant la possibilité de faire des choses comme: ajouter des listes blanches ou des listes noires appliquées à chaque modèle .serialize, toujours sérialiser certaines jointures (de sorte que vous n'avez pas à les ajouter comme arguments tout le temps), et plus!

0
répondu agilgur5 2018-03-26 00:17:26