1. is there any way to serialize models and remove some fields? I.e. I
would like to serialize User for example, but I definitely don't want
the email to be there.
2. is there a way to provide "custom" parts of the serialization? For
example, when serializing a Book I would like to see it's "tags" even if
they are just an array of tags without tag-id etc etc
In general I would like to create some API pages that dump JSON. It
would be great to be able to specify which parts of an object are
"private" and which are "public" and which are "additional" so I could
automatically do this.
Any hints appreciated!
- bram
--
I like python!
UliPad <<The Python Editor>>: http://wiki.woodpecker.org.cn/moin/UliPad
My Blog: http://www.donews.net/limodou
Of course, but that's exactly what I'm trying to avoid...
- bram
Because it's more generic and I don't want to recreate what's done in
the models...
In the end I did it like this:
# MODEL --------------------------------------------
class Book():
hidden_field = ...
user = foreign key
def api_additional(self)
return ({"username": user.username}, ["hidden_field"])
# VIEW --------------------------------------------
def api(request, id, model):
serializer = CustomJSONSerializer()
value = serializer.serialize(model.objects.filter(id=id))
return HttpResponse(value, mimetype='application/javascript')
# CustomJSONSerializer --------------------------------------------
class CustomJSONSerializer(JSONSerializer):
def end_object(self, obj):
super(JSONSerializer, self).end_object(obj)
fields = self.objects[-1]["fields"]
try:
additional_fields, removed_fields = obj.api_additional()
# remove the unwanted fields
for field in removed_fields:
if field in fields.keys():
del fields[field]
# add the additional fields
fields.update(additional_fields)
except AttributeError:
pass
# URLS --------------------------------------------
urlpatterns = patterns('bookshop.api.views',
(r'^models/book/(?P<id>\d+)/$', 'api', {"model": Book}),
Thus getting almost-for-free serialization with hidden fiends and
additional data :-) Perhaps something like this (but a bit smarter)
should go into the Serialization?
- bram
def _get_data(request, obj):
if obj.icon:
icon = '<img class="border" src="/site_media/%s" alt="%s"/>' %
(obj.get_icon_url(), obj.title)
else:
icon = '<img class="border"
src="/site_media/img/book_icon.jpg" alt="%s"/>' % obj.title
authors = [x.username for x in obj.authors.all()]
return ({'id':obj.id, 'icon':icon, 'title':obj.title,
'description':obj.description, 'author':','.join(authors),
'modifydate':obj.modifydate.strftime("%b %d,%Y %I:%m %p")})
def ajax_list(request):
result = []
objs = Book.objects.all()
for o in objs:
result.append(_get_data(request, o))
return json_response(result)
So I'd like write my own data gather method, and it can return other
data just like html snippets except for field value.
And for json method should be:
def json_response(data):
encode = settings.DEFAULT_CHARSET
return HttpResponse(simplejson.dumps(uni_str(data, encode)))
def uni_str(a, encoding=None):
if not encoding:
encoding = settings.DEFAULT_CHARSET
if isinstance(a, (list, tuple)):
s = []
for i, k in enumerate(a):
s.append(uni_str(k, encoding))
return s
elif isinstance(a, dict):
s = {}
for i, k in enumerate(a.items()):
key, value = k
s[uni_str(key, encoding)] = uni_str(value, encoding)
return s
elif isinstance(a, unicode):
return a
elif isinstance(a, (int, float)):
return a
elif isinstance(a, str) or (hasattr(a, '__str__') and
callable(getattr(a, '__str__'))):
if getattr(a, '__str__'):
a = str(a)
return unicode(a, encoding)
else:
return a
You can put json_response and uni_str into a module file. So I think
the work will be not so hard.
The serializer in trunk has a fields option, which only serializes the
fields supplied.
Ex:
serializers.serialize('json', my_user_set, fields=('username', 'id'))
Cheers,
deryck
> The serializer in trunk has a fields option, which only serializes the
> fields supplied.
>
> Ex:
> serializers.serialize('json', my_user_set, fields=('username', 'id'))
This doesn't work at the moment
http://code.djangoproject.com/ticket/3466
But luckily there is also a patch ;)
Regards,
Manoj
Also, this isn't enough...
It would be better/cooler to be able to give "extra" fields and "fields
you DON'T want". The extra could be a callback used on each item in the
sequence:
# note, this is a pretty dumb example :-)
def generate_extra_user_data(user):
return {
"user_tags": [tag.name for tag in user.tag_set.all()],
"username_uppercase": user.username.upper(),
}
serializers.serialize('json',
my_user_set,
extra=generate_extra_user_data,
hidden=["password", "email"])
Now one could go even one step further and add the
generate_extra_user_data and 'hidden' to -for example- the Meta of your
models and call it automatically from the serializer.
- bram
Consider this model:
class Person(models.Model):
... # various fields here.
@staticmethod
def fields_for_serializing():
return [list of those field names that can be serialized]
You can then invoke this method while serializing.
serializers.serialize('json', Person.objects.all(), fields =
Person.fields_for_serializing())
Regards,
Manoj
How do you de-serialize the object back at the ajax response.
class Cart(models.Model):
...
def get_total_quantity():
return quantity;
self.response = self.xmlhttp.responseText;
// parse the response into a JSON object
var json_data = self.response.parseJSON();
alert(json_data.get_total_quantity())
ERROR:
[Exception... "'SyntaxError: parseJSON' when calling method:
[nsIOnReadyStateChangeHandler::handleEvent]" nsresult: "0x8057001c
(NS_ERROR_XPC_JS_THREW_JS_OBJECT)" location: "<unknown>" data: no]
Line 0
Best Wishes,
Kenny