json encoding issue in Python - json

I am attempting a custom encode, but get an error. The following code sample generates an error:
#!/usr/bin/python3
import json
class Contact:
def __init__(self, first, last):
self.first = first
self.last = last
#property
def full_name(self):
return ("{} {}".format(self.first, self.last))
class ContactEncoder(json.JSONEncoder):
def defualt(self, obj):
if isinstance(obj, Contact):
return {"is_contact": 'T'
,"first": obj.first
,"last": obj.last
,"full_name": obj.full_name}
return super().defualt(obj)
if __name__ == "__main__":
c = Contact("Jay", "Loophole")
print(json.dumps(c.__dict__))
print(json.dumps(c, cls=ContactEncoder))
The error generated is:
{"first": "Jay", "last": "Loophole"}
Traceback (most recent call last):
File "json_dump.py", line 26, in <module>
print(json.dumps(c, cls=ContactEncoder))
File "/usr/lib/python3.5/json/__init__.py", line 237, in dumps
**kw).encode(obj)
File "/usr/lib/python3.5/json/encoder.py", line 198, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/usr/lib/python3.5/json/encoder.py", line 256, in iterencode
return _iterencode(o, 0)
File "/usr/lib/python3.5/json/encoder.py", line 179, in default
raise TypeError(repr(o) + " is not JSON serializable")
TypeError: <__main__.Contact object at 0x7ffb3445a400> is not JSON serializable
The default dictionary is successfully displayed, but when a custom encode is passed as a cls parameter, an error occurs.
Any suggestions for the reason for the error?

Here is your updated code after the defUAlt --> defAUlt correction:
import json
class Contact:
def __init__(self, first, last):
self.first = first
self.last = last
#property
def full_name(self):
return ("{} {}".format(self.first, self.last))
class ContactEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, Contact):
return {"is_contact": 'T'
,"first": obj.first
,"last": obj.last
,"full_name": obj.full_name}
return super().default(obj)
if __name__ == "__main__":
c = Contact("Jay", "Loophole")
print(json.dumps(c.__dict__))
print(json.dumps(c, cls=ContactEncoder))
You can check it out live on this page.

Related

How to return single object as a json response inside django function?

I just want to get a single object of User model as a json response. I couldn't figure out how can i do that..
right now i'm getting an error that 'User' object is not iterable
Here is my function:
def some_view(username_to_toggle):
print(username_to_toggle,"User to togle")
user = User.objects.get(username__iexact=username_to_toggle)
print(user,"User object")
user_json = serializers.serialize('json', user,many=False)
print(user,"User json")
return HttpResponse(user_json, content_type='application/json')
TraceBack :
Traceback (most recent call last):
File "/home/hamza/Mydjangoproject/grabpublic/grabpublic/Grab_env/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/home/hamza/Mydjangoproject/grabpublic/grabpublic/Grab_env/lib/python3.6/site-packages/django/core/handlers/base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/home/hamza/Mydjangoproject/grabpublic/grabpublic/Grab_env/lib/python3.6/site-packages/django/core/handlers/base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/hamza/Mydjangoproject/grabpublic/grabpublic/Grab_env/lib/python3.6/site-packages/django/views/generic/base.py", line 71, in view
return self.dispatch(request, *args, **kwargs)
File "/home/hamza/Mydjangoproject/grabpublic/grabpublic/Grab_env/lib/python3.6/site-packages/django/contrib/auth/mixins.py", line 52, in dispatch
return super().dispatch(request, *args, **kwargs)
File "/home/hamza/Mydjangoproject/grabpublic/grabpublic/Grab_env/lib/python3.6/site-packages/django/views/generic/base.py", line 97, in dispatch
return handler(request, *args, **kwargs)
File "/home/hamza/Mydjangoproject/grabpublic/grabpublic/profiles/views.py", line 65, in post
profile_, is_following,json_follower = UserProfile.objects.toggle_follow(request.user, request.user.id ,username_to_toggle,json_follower)
File "/home/hamza/Mydjangoproject/grabpublic/grabpublic/profiles/models.py", line 72, in toggle_follow
json_follower = some_view(username_to_toggle)
File "/home/hamza/Mydjangoproject/grabpublic/grabpublic/profiles/models.py", line 45, in some_view
user_json = serializers.serialize('json', user,many=False)
File "/home/hamza/Mydjangoproject/grabpublic/grabpublic/Grab_env/lib/python3.6/site-packages/django/core/serializers/__init__.py", line 128, in serialize
s.serialize(queryset, **options)
File "/home/hamza/Mydjangoproject/grabpublic/grabpublic/Grab_env/lib/python3.6/site-packages/django/core/serializers/base.py", line 90, in serialize
for count, obj in enumerate(queryset, start=1):
TypeError: 'User' object is not iterable
The serialize method from django.core.serializers doesn't have many option and it always needs a list or a queryset of model objects for the serialization. If you always want to serialize only one object, try using either of those:
first method, using queryset:
def some_view(username_to_toggle):
print(username_to_toggle,"User to togle")
users = User.objects.filter(username__iexact=username_to_toggle)
print(users,"User objects")
user_json = serializers.serialize('json', users)
print(user,"User json")
return HttpResponse(user_json, content_type='application/json')
or a second method, using list:
def some_view(username_to_toggle):
print(username_to_toggle,"User to togle")
user = User.objects.get(username__iexact=username_to_toggle)
print(user,"User object")
user_json = serializers.serialize('json', [user])
print(user,"User json")
return HttpResponse(user_json, content_type='application/json')
many=False or many=True is a feature of Django REST Framework serializators, but their usage is different and more complex as you need to declare a separate serializer for every Model you want to serialize.

How can I use ujson as a Flask encoder/decoder?

I have seen that once can use simplejson as a JSON encoder / decoder within a Flask application like this:
from simplejson import JSONEncoder, JSONDecoder
app.json_encoder = JSONEncoder
app.json_decoder = JSONDecoder
But ujson does not have such objects:
>>> from ujson import JSONEncoder
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: cannot import name 'JSONEncoder' from 'ujson' (/.../site-packages/ujson.cpython-38-x86_64-linux-gnu.so
What I tried
I thought of something like this:
from uuid import UUID, uuid4
import ujson as json
from flask import Flask, jsonify
from flask.json import JSONEncoder
class CustomJSONEncoder(JSONEncoder):
def default(self, obj):
if isinstance(obj, UUID):
return str(obj)
return JSONEncoder.default(self, obj)
def encode(self, o):
return json.dumps(o)
app = Flask(__name__)
app.json_encoder = CustomJSONEncoder
#app.route("/")
def index():
return jsonify({"foo": uuid4()})
app.run()
But I'm uncertain because the help to the decoder shows this:
| decode(self, s, _w=<built-in method match of re.Pattern object at 0x7f6a608404b0>, _PY3=True)
| Return the Python representation of ``s`` (a ``str`` or ``unicode``
| instance containing a JSON document)
|
| raw_decode(self, s, idx=0, _w=<built-in method match of re.Pattern object at 0x7f6a608404b0>, _PY3=True)
| Decode a JSON document from ``s`` (a ``str`` or ``unicode``
| beginning with a JSON document) and return a 2-tuple of the Python
| representation and the index in ``s`` where the document ended.
| Optionally, ``idx`` can be used to specify an offset in ``s`` where
| the JSON document begins.
|
| This can be used to decode a JSON document from a string that may
| have extraneous data at the end.
Is my implementation ok? How would I support those other parameters? When is decode and when raw_decode used?
When I run this, I get:
[2020-10-09 10:54:52,063] ERROR in app: Exception on / [GET]
Traceback (most recent call last):
File "/home/moose/.pyenv/versions/3.8.3/lib/python3.8/site-packages/flask/app.py", line 2447, in wsgi_app
response = self.full_dispatch_request()
File "/home/moose/.pyenv/versions/3.8.3/lib/python3.8/site-packages/flask/app.py", line 1952, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/moose/.pyenv/versions/3.8.3/lib/python3.8/site-packages/flask/app.py", line 1821, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/home/moose/.pyenv/versions/3.8.3/lib/python3.8/site-packages/flask/_compat.py", line 39, in reraise
raise value
File "/home/moose/.pyenv/versions/3.8.3/lib/python3.8/site-packages/flask/app.py", line 1950, in full_dispatch_request
rv = self.dispatch_request()
File "/home/moose/.pyenv/versions/3.8.3/lib/python3.8/site-packages/flask/app.py", line 1936, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "main.py", line 28, in index
return jsonify({"foo": uuid4()})
File "/home/moose/.pyenv/versions/3.8.3/lib/python3.8/site-packages/flask/json/__init__.py", line 370, in jsonify
dumps(data, indent=indent, separators=separators) + "\n",
File "/home/moose/.pyenv/versions/3.8.3/lib/python3.8/site-packages/flask/json/__init__.py", line 211, in dumps
rv = _json.dumps(obj, **kwargs)
File "/home/moose/.pyenv/versions/3.8.3/lib/python3.8/site-packages/simplejson/__init__.py", line 398, in dumps
return cls(
File "main.py", line 14, in encode
return json.dumps(o)
TypeError: UUID('1f45a2bc-c964-48f0-b2f5-9ef7a2557966') is not JSON serializable
You can use a try block like that:
import ujson as json
from flask.json import JSONEncoder
class CustomJSONEncoder(JSONEncoder):
def default(self, obj):
try:
return json.dumps(obj)
except TypeError:
return JSONEncoder.default(self, obj)
from flask import Flask
app = Flask(__name__)
app.json_encoder = CustomJSONEncoder

TypeError Object id is not JSON serializable

I have a Django view that is raising an error when the template tries to render:
TypeError: is not JSON serializable
(Where 76 is the id field)
Here is the view
def view2(request, model1object_id):
model1object = Model1.objects.get(pk=model1object_id)
# HERE
session_object = request.session.get('content')
if session_object:
del request.session['content']
request.session['content'] = model1object
context = {
"model1object": model1object,
....
}
return render(request, 'app/template2.html', context)
Here's my model for Model1:
class Model1(models.Model):
date_field = models.DateField()
another_field = models.CharField(max_length= 50, default="...")
def __str__(self):
return unicode(self.id) or u''
def get_absolute_url(self):
return reverse('app:model1', kwargs={'id': self.id})
EDIT: Traceback ->
Traceback (most recent call last):
File "/Library/Python/2.7/site-packages/django/core/handlers/base.py", line 235, in get_response
response = middleware_method(request, response)
File "/Library/Python/2.7/site-packages/django/contrib/sessions/middleware.py", line 50, in process_response
request.session.save()
File "/Library/Python/2.7/site-packages/django/contrib/sessions/backends/db.py", line 82, in save
obj = self.create_model_instance(data)
File "/Library/Python/2.7/site-packages/django/contrib/sessions/backends/db.py", line 68, in create_model_instance
session_data=self.encode(data),
File "/Library/Python/2.7/site-packages/django/contrib/sessions/backends/base.py", line 91, in encode
serialized = self.serializer().dumps(session_dict)
File "/Library/Python/2.7/site-packages/django/core/signing.py", line 95, in dumps
return json.dumps(obj, separators=(',', ':')).encode('latin-1')
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/__init__.py", line 250, in dumps
sort_keys=sort_keys, **kw).encode(obj)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 207, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 270, in iterencode
return _iterencode(o, 0)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 184, in default
raise TypeError(repr(o) + " is not JSON serializable")
TypeError: <Model1: 76> is not JSON serializable
thanks
The error is because you are trying to save a model instance in the session, and the session middleware cannot serialize it to JSON.
request.session['content'] = model1object
It may be enough to store the id of the object instead of the object itself.
request.session['content_id'] = model1object.id
...
# retrieve from db later
model1object = Model1.objects.get(id=request.session['content_id'])
If you need to store more information in the session than the id, then you'll have to convert it to a format that is JSON serializable. For a simple model, it might be easiest to create a Python dict.
request.session['content'] = {
'id': model1object.id,
'name': model1object.name,
...
}
For more complicated models, you could look at the docs on serializing Django objects.

Handling Django form.save() ValueError

I am a newbie to Django error handling and I spent a week trying to figure out what exactly goes wrong when trying to update a MySQL table using Django forms. I end up with ValueError: invalid literal for int() with base 10: '\x01' error. I tried to surround the erroneous code with try catch block trapping valueError and printing the row sql query, and here's what I get.
The code:
def updateTask(request, task_id):
#cur_usr_sale_point = PersonUnique.objects.filter(employees__employeeuser__auth_user = request.user.id).values_list('agreementemployees__agreement_unique__sale_point_id',flat=True)
selected_task = Tasks.objects.get(id=task_id)
responsible_people = TaskResponsiblePeople.objects.get(task_id = task_id)
task_table = Tasks. objects.all()
if request.method == 'POST':
task_form = TaskForm(request.POST,instance=selected_task)
responsible_people_form = TaskResponsiblePeopleForm(request.POST, instance = responsible_people)
if task_form.is_valid() and responsible_people_form.is_valid():
responsible_people_instance = responsible_people_form.save(commit=False)
try:
responsible_people_instance.task = task_form.save()
responsible_people_form.save()
except ValueError:
from django.db import connection
print connection.queries[-1]
return HttpResponseRedirect(reverse('task_list'))
Print gives me an absolutely valid MySQL Select-statement (to my surpise, I expected an update-statement).
The traceback without try-catch block:
Internal Server Error: /task_list/update_task/200/
Traceback (most recent call last):
File "C:\Python27\lib\site-packages\django\core\handlers\base.py", line 149, in get_response
response = self.process_exception_by_middleware(e, request)
File "C:\Python27\lib\site-packages\django\core\handlers\base.py", line 147, in get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "\\10.8.0.1\share\djprj\djprj\djprj\task\views.py", line 101, in updateTask
task_form.save();
File "C:\Python27\lib\site-packages\django\forms\models.py", line 451, in save
self.instance.save()
File "C:\Python27\lib\site-packages\django\db\models\base.py", line 700, in save
force_update=force_update, update_fields=update_fields)
File "C:\Python27\lib\site-packages\django\db\models\base.py", line 728, in save_base
updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
File "C:\Python27\lib\site-packages\django\db\models\base.py", line 793, in _save_table
forced_update)
File "C:\Python27\lib\site-packages\django\db\models\base.py", line 843, in _do_update
return filtered._update(values) > 0
File "C:\Python27\lib\site-packages\django\db\models\query.py", line 645, in _update
return query.get_compiler(self.db).execute_sql(CURSOR)
File "C:\Python27\lib\site-packages\django\db\models\sql\compiler.py", line 1149, in execute_sql
cursor = super(SQLUpdateCompiler, self).execute_sql(result_type)
File "C:\Python27\lib\site-packages\django\db\models\sql\compiler.py", line 837, in execute_sql
sql, params = self.as_sql()
File "C:\Python27\lib\site-packages\django\db\models\sql\compiler.py", line 1117, in as_sql
val = field.get_db_prep_save(val, connection=self.connection)
File "C:\Python27\lib\site-packages\django\db\models\fields\__init__.py", line 728, in get_db_prep_save
prepared=False)
File "C:\Python27\lib\site-packages\django\db\models\fields\__init__.py", line 720, in get_db_prep_value
value = self.get_prep_value(value)
File "C:\Python27\lib\site-packages\django\db\models\fields\__init__.py", line 1853, in get_prep_value
return int(value)
ValueError: invalid literal for int() with base 10: '\x01'
[10/Apr/2016 11:15:46] "POST /task_list/update_task/200/ HTTP/1.1" 500 126245
Help me out please !!!
EDIT: added is_valid method
You need to first use the form's is_valid method:
A Form instance has an is_valid() method, which runs validation routines for all its fields. When this method is called, if all fields contain valid data.
from django.shortcuts import render
from django.http import HttpResponseRedirect
from .forms import NameForm
def get_name(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = NameForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
return HttpResponseRedirect('/thanks/')
# if a GET (or any other method) we'll create a blank form
else:
form = NameForm()
return render(request, 'name.html', {'form': form})
Source: Django Docs: Working with forms
I would recommend that you read the above documentation.

Scrapy Spider for JSON Response

I am trying to write a spider which crawls through the following JSON response:
http://gdata.youtube.com/feeds/api/standardfeeds/UK/most_popular?v=2&alt=json
How would the spider look if I would want to crawl all the titles of the videos? All my Spiders dont work.
from scrapy.spider import BaseSpider
import json
from youtube.items import YoutubeItem
class MySpider(BaseSpider):
name = "youtubecrawler"
allowed_domains = ["gdata.youtube.com"]
start_urls = ['http://www.gdata.youtube.com/feeds/api/standardfeeds/DE/most_popular?v=2&alt=json']
def parse(self, response):
items []
jsonresponse = json.loads(response)
for video in jsonresponse["feed"]["entry"]:
item = YoutubeItem()
print jsonresponse
print video["media$group"]["yt$videoid"]["$t"]
print video["media$group"]["media$description"]["$t"]
item ["title"] = video["title"]["$t"]
print video["author"][0]["name"]["$t"]
print video["category"][1]["term"]
items.append(item)
return items
I always get following error:
2014-01-05 16:55:21+0100 [youtubecrawler] ERROR: Spider error processing <GET http://gdata.youtube.com/feeds/api/standardfeeds/DE/most_popular?v=2&alt=json>
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/twisted/internet/base.py", line 1201, in mainLoop
self.runUntilCurrent()
File "/usr/local/lib/python2.7/dist-packages/twisted/internet/base.py", line 824, in runUntilCurrent
call.func(*call.args, **call.kw)
File "/usr/local/lib/python2.7/dist-packages/twisted/internet/defer.py", line 382, in callback
self._startRunCallbacks(result)
File "/usr/local/lib/python2.7/dist-packages/twisted/internet/defer.py", line 490, in _startRunCallbacks
self._runCallbacks()
--- <exception caught here> ---
File "/usr/local/lib/python2.7/dist-packages/twisted/internet/defer.py", line 577, in _runCallbacks
current.result = callback(current.result, *args, **kw)
File "/home/bxxxx/svn/ba_txxxxx/scrapy/youtube/spiders/test.py", line 15, in parse
jsonresponse = json.loads(response)
File "/usr/lib/python2.7/json/__init__.py", line 326, in loads
return _default_decoder.decode(s)
File "/usr/lib/python2.7/json/decoder.py", line 365, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
exceptions.TypeError: expected string or buffer
found two issues in your code:
start url is not accessible, I took out the www from it
changed json.loads(response) to json.loads(response.body_as_unicode())
this works well for me:
class MySpider(BaseSpider):
name = "youtubecrawler"
allowed_domains = ["gdata.youtube.com"]
start_urls = ['http://gdata.youtube.com/feeds/api/standardfeeds/DE/most_popular?v=2&alt=json']
def parse(self, response):
items = []
jsonresponse = json.loads(response.body_as_unicode())
for video in jsonresponse["feed"]["entry"]:
item = YoutubeItem()
print video["media$group"]["yt$videoid"]["$t"]
print video["media$group"]["media$description"]["$t"]
item ["title"] = video["title"]["$t"]
print video["author"][0]["name"]["$t"]
print video["category"][1]["term"]
items.append(item)
return items