ProblemaDjango REST quadro e rapporti generici
Ho un modello con i seguenti generici campi chiave esterna standard:
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
event_object = generic.GenericForeignKey('content_type', 'object_id')
Secondo la documentazione del framework REST, posso effettuare le seguenti operazioni a puntate questo correttamente:
class WhateverSerializer(serializers.ModelSerializer):
event_object = serializers.RelatedField(source='event_object')
Questo funziona bene, ma in altre due situazioni correlate, non riesco a far funzionare le cose:
- Vorrei utilizzare
HyperlinkedRelatedField
. Questo campo richiede l'argomento view_name, qualcosa che non posso dichiarare poiché il nome della vista varia con il modello correlato. Ho risolto questo problema utilizzandoSerializerMethodField
, creando un'istanza diHyperlinkedIdentityField
in fase di runtime e restituendo il suo metodofield_to_native
(vedere lo snippet di seguito). Questo non si sente molto elegante. - Vorrei nidificare l'oggetto correlato direttamente nella serializzazione dicendo
event_object = SoAndSoSerializer(source='event_object')
. L'unica soluzione che riesco a vedere è camminare ogni*Serializer
che ho definito e verificare quale sia il modello corretto, quindi usarlo. Di nuovo, questo non si sente molto elegante.
Domande
è HyperlinkRelatedField pensato per funzionare su una relazione generica? Sto solo facendo un errore? C'è una soluzione ovvia per scegliere il giusto *Serializer
che mi manca?
frammento di codice
La soluzione poco elegante di cui al punto 1 di cui sopra proiettile:
class WhateverSerializer(DefaultSerializer):
event_object_url = serializers.SerializerMethodField('get_related_object_url')
# ...
def get_related_object_url(self, obj):
obj = obj.event_object
default_view_name = '%(model_name)s-detail'
format_kwargs = {
'app_label': obj._meta.app_label,
'model_name': obj._meta.object_name.lower()
}
view_name = default_view_name % format_kwargs
s = serializers.HyperlinkedIdentityField(source=obj, view_name=view_name)
s.initialize(self, None)
return s.field_to_native(obj, None)
Si noti che è necessario utilizzare l'argomento "origine" per un campo solo se la sorgente è diversa dal nome del campo. Puoi lasciarlo nel caso 'event_object'. –