Serialization of an object with foreign key into json - django

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.

Related

Mongoengine EmbeddedDocumentListField // I can only access the get menthod

I am creating a database for my school. There is a Student Document that has an EmbeddedDocumentListField of Adults. I am trying to update existing EmbeddedDocuments using the EmbeddedDocumentListField methods but both save() and update() give me errors. get() seems to work though.
class Adult(EmbeddedDocument):
relation = StringField() # Adult, Mother, Father, Grandmother...
...
notes = StringField()
class Student(Document):
afname = StringField()
alname = StringField()
...
adults = EmbeddedDocumentListField('Adult')
I am able to successfully use the get method
#app.route('/editadult/<aeriesid>/<adultoid>')
def editadult(aeriesid,adultoid):
editUser = User.objects.get(aeriesid=aeriesid)
editAdult = editUser.adults.get(oid=adultoid)
This returns the object named editAdult with the attributes as expected but not the methods. I now want to update the values in that Object. I am able to see the methods I want to call by doing.
dir(editUser.adults)
But can't see the methods with
dir(editAdult)
From my reading of the docs I should be able to do this.
editAdult.update(fname="Juanita", lname="Sanchez")
This gives the error: AttributeError: 'Adult' object has no attribute 'update'.
But can't figure out how to use the methods on that context.
I tried
editAdult.fname = "Juanita"
editAdult.lname = "Sanchez"
editAdult.save()
But that gives the error: AttributeError: 'Adult' object has no attribute 'save'
The documentation is sparse. Mongoengine tells me what the methods are but no examples.
http://docs.mongoengine.org/apireference.html#embedded-document-querying
And GitHub gives good examples but I couldn't get them to work.
https://github.com/MongoEngine/mongoengine/pull/826
I am using Mongoengine 0.20.0
After a lot of trial and error I figured this out. With this data structure:
class Adult(EmbeddedDocument):
relation = StringField() # Adult, Mother, Father, Grandmother...
fname = StringField()
lname = StringField()
...
notes = StringField()
class Student(Document):
afname = StringField()
alname = StringField()
...
adults = EmbeddedDocumentListField('Adult')
I then created this Flask Route
#app.route('/editadult/<aeriesid>/<adultoid>')
def editadult(aeriesid,adultoid):
editUser = User.objects.get(aeriesid=aeriesid)
editAdult = editUser.adults.get(oid=adultoid)
adultoid is the unique identifier for the adult and aeriesid is the unique identifier for the student so I know that both of these will retrieve exactly one record.
The part that I was missing is that while the editAdult Object contains exactly the values that I want, it is NOT an EmbeddedDocumentListObject so it does not contain the methods. So, that get() command above is the basic MongoEngine get() and NOT the get() method from the EmbeddedDocumentFieldList. (I show the EmbeddedDocumentListField get() below)
Here is what I was missing. This is how you use the update() method in the EmbeddedDocumentListField.
editUser.adults.filter(oid=adultoid).update(
relation = form.relation.data,
fname = form.fname.data,
lname = form.lname.data,
...
notes = form.notes.data
)
I am not sure if this update command would update all of the filtered records. In my case, it is only possible that one record is returned because I am filtering on a uniqueid. Next, it turns out the EmbeddedDocumentListField() update() does NOT save like it does in the base update() method so you then have to do this. This fact is actually well documented in the MongoEngine docs.
http://docs.mongoengine.org/apireference.html?highlight=embedded%20documents#embedded-document-querying
editUser.adults.filter(oid=adultoid).save()
Finally, there is another way to do the original get() command:
editAdult2 = editUser.adults.filter(oid=adultoid).get()
For the sake of completeness, here is the Flask route to delete an EmbeddedDocument record
#app.route('/deleteadult/<aeriesid>/<adultoid>')
def deleteadult(aeriesid,adultoid):
editUser = User.objects.get(aeriesid=aeriesid)
editAdult = editUser.adults.get(oid=adultoid)
editUser.adults.filter(oid=adultoid).delete()
editUser.adults.filter(oid=adultoid).save()
I hope this is helpful to others. The process to learn this was crazy hard and mostly just trial and error. I considering going back to SQLAlchemy. :(

How to pass non-form data in django form object?

I have a data dictionary and want to validate and clean that data to store in database table as defined in models.py
My approach was creating a form class then create an instance of that form class and pass data dictionary instead of request.POST in the view.py.
But this is not working. No error, but cleaned_data returning an empty dictionary.
data = {
'story_title': i.title.text,
'story_source': Sources.objects.get(source_url= source_url),
'pub_date': i.pubDate.text[5:16],
'body_text': des,
'url': i.link.text
}
story_form = StoryForm(data)
if story_form.is_valid():
story_data = story_form.cleaned_data
new_story = Stories(
story_title = story_data['story_title'],
story_source = story_data['story_source'],
pub_date = story_data['pub_date'],
body_text = story_data['body_text'],
url = story_data['url']
)
new_story.save()
I am not confirm that my approach is right or wrong.
While searching for solution I came across HttpRequest.body in Django docs which only says that HttpRequest.body is used to populate form instance with the non-form data / raw data (nothing about how to use).

How to return only one field in tastypie?

Suppose I have a resource like below..
class PostResource(ModelResource):
children = fields.ToManyField('MyApp.api.resources.PostResource',
attribute='comments', full=True, null=True)
Basically, I want to return this children field only and flatten it.
It will look like
[ {child-1-data}, {child-2-data} ]
rather than
{ children: [ {child-1-data}, {child2-data} ] }
How can I do that?
Additionaly, if I want a different representation of the same model class, should I create a new resource class as bellow?
class PostNormalResource(ModelResource):
class Meta:
queryset= models.Post.objects.all()
fields = ['text', 'author']
Not really the answer you are looking for but some discoveries I made while digging.
Normally you would modify the bundle data in dehydrate. See the tastypie cookbook.
def dehydrate(self, bundle):
bundle.data['custom field'] = "This is some additional text on the resource"
return bundle
This would suggest you could manipulate your PostResource's bundle data along the lines of:
def dehydrate(self, bundle):
# Replace all data with a list of children
bundle.data = bundle.data['children']
return bundle
However this will error, AttributeError: 'list' object has no attribute 'items', as the tastypie serializer is looking to serialize a dictionary not a list.
# "site-packages/tastypie/serializers.py", line 239
return dict((key, self.to_simple(val, options)) for (key, val) in data.data.items())
# .items() being for dicts
So this suggests you need to look at different serializers. (Or just refer to post['children'] when processing your JSON :-)
Hope that helps get you in the right direction
And secondly yes, if you want a different representation of the same model then use a second ModelResource. Obviously you can subclass to try and avoid duplication.
You could try overriding the alter_detail_data_to_serialize method. It it called right after whole object has been dehydrated, so that you can do modifications on the resulting dictionary before it gets serialized.
class PostResource(ModelResource):
children = fields.ToManyField('MyApp.api.resources.PostResource',
attribute='comments', full=True, null=True)
def alter_detail_data_to_serialize(self, request, data):
return data.get('children', [])
As to different representation of the same model - yes. Basically, you shouldn't make a single Resource have many representations as that would lead to ambiguity and would be difficult to maintain.

Passing JSON with 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.

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/