Passing JSON with Django - django

I'm passing information to a Processing sketch from a Django backend. The problem arises with "lectures", it seems that it is not serializable. I'm missing something very basic methinks.
def get(request, last_update = None):
timestamp = time.time()
if last_update:
last_update = datetime.fromtimestamp(float(last_update))
lectures = Lecture.objects.all().filter(datetime_edit__gt=last_update)
else:
lectures = Lecture.objects.all()
updates = {'timestamp': timestamp, 'lectures': lectures}
print updates
return HttpResponse(json.dumps(updates), mimetype="application/json")
Here is the response that I'm getting in the browser.
[<Lecture: whales>, <Lecture: cats>, <Lecture: rain>, <Lecture: china>] is not JSON serializable

QuerySet cannot be serialized in this manner. Use .values() and list() to turn it into a basic Python structure (i.e. a list of dicts) first.

The JSON serialize does not support serialization of arbitrary class instances. You should convert Lecture records into dictionaries before serializing.

Related

Python Marshmallow & SQL-Alchemy - update/store complex objects

Hello community!
So I a a student and relatively new to python, implementing a CRUD-API right now, based on SQL-Alchemy, restx and Flask. For the conversion of the database-objects, I use Marshmallow. The database is a legacy database which can not be changed. In the database, there are some attributes that are encoded, for example a list of labs is encoded as string with the lab names in it. I use converters to cover them, as shown here:
gene_bp = Blueprint('gene', __name__)
api = createApi(gene_bp)
class FooDto(SQLAlchemyAutoSchema):
class Meta:
model = Foo
include_fk = True
include_relationships = True
load_instance = True
bar = decimal_converter.DecimalEncoder()
The Endpoint does look like this:
#api.route('/api/<string:id>')
#api.doc()
class FooRoute(Resource):
def get(self, id):
foo = get_foo_or_abort(id)
if foo:
return createSuccessResponse(FooDto().dump(foo))
The reading-part of the API is no problem with this, but now I struggle with the write/update part. This is my code until now:
#api.route('/api/<string:id>')
#api.doc()
class FooRoute(Resource):
#api.doc(params={'dto': 'Item to update', 'id': 'object id'})
def put(self, id):
fooToStore: FooDto = api.payload
if not fooToStore:
abort(400)
if fooToStore['id'] != id:
abort(400)
# todo: payload to database object
# todo: save payload to database
db.session.commit()
return updatedFoo
So as you can see, there are two ToDos open:
How do i convert the DTO back to a database object, without manual mapping? I understand that there is this method
fooToUpdate = dto.load(geneToStore)
but how do I add the needed complexity for encoded attributes like the lab list, or foreign keys to it?
What is the best practice in storing the data to the database?
Thank you all very much!

How to format datetime in a serialized model Django

I have the following model
class MyModel(models.Model):
firstDate = models.DateTimeField(auto_now_add=True)
another = models.CharField(max_length=30)
I serialize it to JSON with
query = MyModel.objects.all()
data = serializers.serialize('json', query, use_natural_foreign_keys=True)
The DateTimeField returns the following format:
2017-12-19T22:50:04.328Z
The desired format is:
2017-12-19 22:50:04
Is there a simple way to achieve this without using the queryset.values() and queryset.extra() methods?
You'll want to create your own subclass of DjangoJSONEncoder - which is a subclass of Python's standard JSON encoder that implements (among other things) the functionality that you wish to change.:
If you look at the source code, it's pretty trivial. You'll want to change the section starting with:
if isinstance(o, datetime.datetime):
to have the method return the datetime in the format you desire.
class MyJSONEncoder(DjangoJSONEncoder):
def default(self, o):
if isinstance(o, datetime.datetime):
# Your implementation here
return super().default(o)
As suggested by aircraft, I treat it in the front-end with the JavaScript built-in Date implementation (didn't know about it until now). It's perfect for manipulating formats and locales.
In specific, I used this object function: Date.prototype.toLocaleFormat

Serialization of an object with foreign key into json

this is in Django:
data = []
data += serializers.serialize("json", conversation_deal)
data += serializers.serialize("json", deal_statuses)
dat = serializers.serialize("json", data)
return HttpResponse(dat)
I would like to save one round trip to the webservice and combine two jsons into one.
What I tried to do was to serialize each object into json and add them into an array and serialize them again as json. But it throws an exception.
I also tried to put the two python objects into the array and serialize them all into json, which also failed.
How is this usually done?
Update:
Exception:
str: 'str' object has no attribute '_meta'
Update 2:
I have some more information, and it seems its somehow Django related the way it serializes the objects.
the following works perfectly fine:
deal_statuses = DealStatus.objects.all()
data = serializers.serialize("json", deal_statuses)
return HttpResponse(data)
but this fails..
conversation_deal = Conversation_Deal.objects.filter(conversation_id__in=call_id)
data = serializers.serialize("json", conversation_deal)
return HttpResponse(data)
This is how Conversation_Deal is modelled:
class Conversation_Deal(models.Model):
conversation = models.ForeignKey('Conversation')
deal = models.ForeignKey('Deal')
status = models.ForeignKey(DealStatus, null=True, blank=True)
I found something related to inherited classes documentation pointing this out why...Even though I am not inheriting, but the same process worked in my case. Hope this helps someone else. I will post this as an answer soon.
I found the solution.
Literally since Conversation_Deal has a foreignkey to DealStatus class. It needs to know about it during serialization.
all = list(Conversation_Deal.objects.filter(conversation_id__in=call_id)) + list(DealStatus.objects.all())
return HttpResponse(simplejson.dumps(to_json), mimetype='application/json')
Hope this helps somebody else.

Can't Return JSON object using MongoEngine Pymongo with Django?

So I'm trying to return a JSON object for a project. I've spent a few hours trying to get Django just returning the JSON.
Heres the view that we've been working with:
def json(request, first_name):
user = User.objects.all()
#user = User.objects.all().values()
result = simplejson.dumps(user, default=json_util.default)
return HttpResponse(result)
Here's my model:
class User(Document):
gender = StringField( choices=['male', 'female', 'Unknown'])
age = IntField()
email = EmailField()
display_name = StringField(max_length=50)
first_name = StringField(max_length=50)
last_name = StringField(max_length=50)
location = StringField(max_length=50)
status = StringField(max_length=50)
hideStatus = BooleanField()
photos = ListField(EmbeddedDocumentField('Photo'))
profile =ListField(EmbeddedDocumentField('ProfileItem'))
allProfile = ListField(EmbeddedDocumentField('ProfileItem')) #only return for your own profile
This is what it's returning:
[<User: User object>, <User: User object>] is not JSON serializable
Any thoughts on how I can just return the JSON?
With MongoEngine 0.8 or greater, objects and querysets have a to_json() method.
>>> User.objects.to_json()
simplejson.dumps() doesn't know how to "reach into" your custom objects; the default function, json_util.default must just be calling str() or repr() on your documents. (Is json_util custom code you've written? If so, showing its source here could prove my claim.)
Ultimately, your default function will need to be able to make sense of the MongoEngine documents. I can think of at least two ways that this might be implemented:
Write a custom default function that works for all MongoEngine documents by introspecting their _fields attribute (though note that the leading underscore means that this is part of the private API/implementation detail of MongoEngine and may be subject to change in future versions)
Have each of your documents implement a as_dict method which returns a dictionary representation of the object. This would work similarly to the to_mongo method provided on documents by MongoEngine, but shouldn't return the _types or _cls fields (again, these are implementation details of MongoEngine).
I'd suggest you go with option #2: the code will be cleaner and easier to read, better encapsulated, and won't require using any private APIs.
As dcrosta suggested you can do something like this, hope that will help you.
Document definition
class MyDocument(Document):
# Your document definition
def to_dict(self):
return mongo_to_dict_helper(self)
helper.py:
from mongoengine import StringField, ListField, IntField, FloatField
def mongo_to_dict_helper(obj):
return_data = []
for field_name in obj._fields:
if field_name in ("id",):
continue
data = obj._data[field_name]
if isinstance(obj._fields[field_name], StringField):
return_data.append((field_name, str(data)))
elif isinstance(obj._fields[field_name], FloatField):
return_data.append((field_name, float(data)))
elif isinstance(obj._fields[field_name], IntField):
return_data.append((field_name, int(data)))
elif isinstance(obj._fields[field_name], ListField):
return_data.append((field_name, data))
else:
# You can define your logic for returning elements
return dict(return_data)

How do I save a Django Model from request.POST?

I'm trying to save a new object from a django model using a POST data querydict. This is part of a PISTON handler. I've seen this done in numerous examples, but I just can't get it to work.
Here is my code:
class FestHandler(BaseHandler):
model = Deal
def create(self, request):
"""
Creates a new fest.
"""
attrs = self.flatten_dict(request.POST)
postcopy = request.POST.copy()
if self.exists(**attrs):
return rc.DUPLICATE_ENTRY
else:
loc = Location.objects.get(pk=attrs['location'])
postcopy['location'] = loc
fest = Fest(postcopy)
fest.save()
return fest
Here is the error I receive every time:
Exception was: int() argument must be a string or a number, not 'QueryDict'
I realize what the error means, so basically I am asking how I can save a new "Fest" by passing in the whole POST dictionary without having to type in the keys manually every time like this:
loc = Location.objects.get(pk=attrs['location'])
fest = Fest(
location=loc,
name=attrs['name'],
description=attrs['description'],
details=attrs['details'],
)
Thanks for your help!
First, I think you'll be happier of you explicitly make your PK's into integers.
loc = Location.objects.get(pk=int(attrs['location']))
Second, you should use a Form.
It validates the fields for you.
It will create the Model object from the Form object.
Read this. http://docs.djangoproject.com/en/1.2/topics/forms/modelforms/