Package: hypermediachannels
A Hyper Media style serializer forDjangoChannelsRestFramework.API USAGEThis is a collection of serialisers and serialiser fields that creats a
hypermidea style like PKSetting up your consumersAll of your consumers should be mapped through aAsyncJsonWebsocketDemultiplexer.fromchannelsmultiplexerimportAsyncJsonWebsocketDemultiplexerfromdjangochannelsrestframework.genericsimportGenericAsyncAPIConsumerfromhypermediachannels.serializersimportHyperChannelsApiModelSerializerclassUserSerializer(HyperChannelsApiModelSerializer):classMeta:model=Userfields=('@id','username')classUserConsumer(GenericAsyncAPIConsumer):queryset=User.objects.all()serializer_class=UserSerializerclassMainDemultiplexer(AsyncJsonWebsocketDemultiplexer):applications={'users':UserConsumer,}Then when configuring your Channels Application add theMainDemultiplexeras your main consumer. This way all Websocket connections on that URL will run through theDemultiplexer. SeeDjangoChannelsRestFrameworkfor more deaitls on how to write consumers.HyperChannelsApiModelSerializerThis can be used inplace of the DRFModelSerializer. It will (if you
include@idin thefieldslist) add a self reference to the
model being displayed)egUsermodel Serialiser might respond like this if its fields are('@id','username', 'profile'){@id:{stream:'user',payload:{action:'retrieve',pk:1023}},username:'bob@example.com',profile:{stream:'profile',payload:{action:'retrieve',pk:23}}}This will under the hood useHyperlinkedIdentityFieldto create the@idandprofilefields and they will (by default) return theseretrieveobjects.Why do we do this.this means that if we then need to lookup thatprofilefor this user
we can just send the msg:{stream:'profile',payload:{action:'retrieve',pk:23}}Down the websocket and we will get that item, the frontend code does not
need to track all of these lockup logic, (consider that some models
might have lookup that is not based onpkfor example).If you need to define a different set of lookup params. You can use thekwarg_mappings,stream_nameandaction_namekwargs to
override this.eg:classUserSerializer(HyperChannelsApiModelSerializer):classMeta:model=get_user_model()fields=('@id','username','profile')extra_kwargs={'profile':{'action_name':'user_profile','kwarg_mappings':{'user_pk':'self.pk','team_pk':'team.pk'}},}thekwarg_mappingswill set the value in the responseuser_pkby
extracting thepkvalue on from theUserinstance.(pre-appendingselfto thekwarg_mappingsvalue means it will do
the lookup based on the instance parsed to the parentSerializerrather than the instance for this field. In this case a user profile).so the above would return:{@id:{stream:'user',payload:{action:'retrieve',pk:1023}},username:'bob@example.com',profile:{stream:'user_profile',payload:{action:'retrieve',user_pk:1023,team_pk:234234}}}You can use.to access nested values eg.profile.team.name.Alternatively you can create fields as you would in DRF.classUserSerializer(HyperChannelsApiModelSerializer):team=HyperChannelsApiRelationField(source='profile.team',kwarg_mappings={'member_username':'self.username'})classMeta:model=get_user_model()fields=('@id','username','team')this will return:{@id:{stream:'user',payload:{action:'retrieve',pk:1023}},username:'bob@example.com',team:{stream:'team',payload:{action:'retrieve',member_username:'bob@example.com'}}}If you reference a Many field theHyperChannelsApiModelSerializerwill do some magic so that:classUserSerializer(HyperChannelsApiModelSerializer):friends=HyperChannelsApiRelationField(source='profile.friends')classMeta:model=get_user_model()fields=('@id','username','friends')extra_kwargs={'friends':{'kwarg_mappings':{'user_pk':'self.user.pk',}},}Addingextra_kwargsfor anyManyfield can be important so that
you can controle the lookup params used.NOTEallManyfields (forwards and backwards) will extract
values from the parent instance regardless of if you useself.in
thekwarg_mappingsvalue.)this will return:{@id:{stream:'user',payload:{action:'retrieve',pk:1023}},username:'bob@example.com',friends:{stream:'user_profile',payload:{action:'list',user_pk:1023}}}Remember you can also override the@idlookup/action and stream if
needed, eg:extra_kwargs={'@id':{'action_name':'subscribe_status','kwarg_mappings':{'username':'username'}},}Returning Many items.Expect to get:[{stream:'user',payload:{action:'retrieve',pk:1023}},{stream:'user',payload:{action:'retrieve',pk:234}},{stream:'user',payload:{action:'retrieve',pk:103223}},]Rather than getting a fully expanded value for each instance you will
rather just get a list ofhyper media pathsyou can use to lookup
the instance you need.If you need to override thestreamactionorlookupdo this:classUserSerializer(HyperChannelsApiModelSerializer):classMeta:model=Userfields=('@id','username')many_stream_name='active_users'many_kwarg_mappings={'username':'username'}many_action_name='subscribe'