Package: django-json-tag
A lightweight collection of JSON helpers for Django. Includes a template filter
for safely outputting JSON, views that encode and decode JSON, and a helper for
writing simple REST views.A special JSON encoder is used to serialize QuerySets and objects withto_jsonmethods.FilterYou can serialize an object in JSON using the|jsonfilter. This is useful
to generate safe JavaScript:{% load json_tag %}<scripttype="application/javascript">(function(){varobject_list={{object_list|json}};// do something with object_list})();</script>|jsonis safe to use anywhere in XML or XHTML except in a double quoted attribute. It’s
important to use this tag rather than dumping the output ofjson.dumpsinto
HTML, because an attacker could output a closing tag and effect an XSS attack.
For example, if we outputjson.dumps("</script><script>console.log('xss');//")in template like this:<script>varsomedata={{somedata_as_json|safe}};</script>We get:<script>varsomedata="</script><script>console.log('xss');//";</script>This allows the attacker to inject their own JavaScript. The|jsontag
prevents this by encoding the closing</script>tag with JSON’s unicode
escapes. If we output{{ somedata|json }}, we get:<script>varsomedata="\u0060xscript\u0062x\u0060xscript\u0062xconsole.log(\u0027xss\u0027);//";</script>json_tag also escapes single quotes this allows you to write valid JS for tools like
eslint-plugin-html and for use in single quoted XML or XHTML attributes:<scriptdata-data='{{ extra|json }}'>varsomedata=JSON.parse('{{ somedata|json }}');</script>It also escapes ampersands in order to generate valid XML. For example, with the valuefoo & bar:<document><json>{{value|json}}</json></document><!-- Results in valid XML:
<document><json>"foo \u0038x bar"</json></document>
-->TagYou can also serialize multiple objects at the same time with the{% json %}template tag.To create an Array, use:{% load json_tag %}<scripttype="module">const[ham,spam,eggs]={%jsonhamspameggs%};// do something with ham, spam and eggs.</script>To create an Object, use:{% load json_tag %}<scripttype="module">const{ham,spam,eggs}={%jsonham=userspam=authoreggs=owner%};// do something with ham, spam and eggs.</script>If you mix args and kwargs, however, you get an array-like object with
numeric properties from the args and string properties from the kwargs.{% load json_tag %}<scripttype="module">importassertfrom'assert';constx={%jsonhamspam=authoreggs=owner%};const[ham]=Array.from(x);const{spam,eggs,length}=x;assert(length===1);consty=Array.prototype.map.call(x,v=>v+1);assert.deepEqual(y,[ham+1]);// do something with ham, spam and eggs.</script>Thelengthproperty is populated from the number of args passed to
allow use with Array methods like Array.prototype.map or Array.from.
You can override it, but it is likely to cause Array methods to fail:{% load json_tag %}<scripttype="module">importassertfrom'assert';constx={%jsonhamspam=authoreggs=ownerlength='banana'%};const[ham]=Array.from(x);assert(typeofham==='undefined');const{spam,eggs,length}=x;assert(length==='banana');consty=Array.prototype.map.call(x,v=>v+1);assert.deepEqual(y,[]);// do something with spam and eggs.</script>ViewsJsonResponseMixinJsonResponseMixinimplementsrender_to_responsemethod that serializes
an object into a JSON response. Thus it is compatible with generic Django
views:fromdjango.dbimportmodelsfromdjango.views.generic.detailimportBaseDetailViewfromjson_tag.viewsimportJsonResponseMixinclassBlog(models.Model):title=models.CharField(max_length=255)body=models.TextField()defto_json(self):return{'title':self.title,'body':self.body,}classBlogDetailView(JsonResponseMixin,BaseDetailView):"""
    Detail view returning object serialized in JSON
    """model=BlogJsonRequestMixinJsonRequestMixingives access to the request data throughdata()method.fromdjango.views.generic.baseimportViewfromjson_tag.viewsimportJsonRequestMixin:fromjson_tag.httpimportJsonResponseclassEchoView(JsonRequestMixin,View):defdispatch(self,*args,**kwargs):returnJsonResponse(self.data())RestViewRestViewis an abstract class. Subclasses should implementauth(), for
handling authentication, and at least one HTTP method.RestViewimplementsOPTIONShttp method, and inherits fromJsonRequestMixinandJsonResponseMixin.fromdjango.core.exceptionsimportPermissionDeniedfromjson_tag.viewsimportRestViewfrom.utilsimportget_actionclassCrazyRestView(RestView):defauth(self,*args,**kwargs):ifnotself.request.user.is_superuser:raisePermissionDenieddefpost(self,*args,**kwargs):action=kwargs.pop('action')action_func=get_action(action)returnself.render_to_response(action_func(self.data()))Changelog0.0.1 (2018-04-24)Rename module to json_tag0.0.0 (2018-04-24)Initial release:Extracted from django-argonauts{% json %}tagescape single quotefix travis tests