Converting JSON to model instance in Django - django

What's the best way in django to update a model instance given a json representation of that model instance.
Is using deserialize the correct approach? Are there tutorials available out there?

The best approach would be to utilize one of the existing Django applications that support serializing model instances to and from JSON.
In either case, if you parse the JSON object to a Python dictionary, you can basically use the QuerySet.update() method directly.
So, say you get a dictionary where all the keys map to model attributes and they represent the values you'd want to update, you could do this:
updates = { # Our parsed JSON data
'pk': 1337,
'foo': 'bar',
'baz': 192.05
}
id = updates.pop('pk') # Extract the instance's ID
Foo.objects.filter(id=id).update(**updates) # Update the instance's data

Related

Django Rest Framework: Disable save in update

It is my first question here, after reading the similar questions I did not find what I need, thanks for your help.
I am creating a fairly simple API but I want to use best practices at the security level.
Requirement: There is a table in SQL Server with +5 million records that I should ONLY allow READ (all fields) and UPDATE (one field). This is so that a data scientist consumes data from this table and through a predictive model (I think) can assign a value to each record.
For this I mainly need 2 things:
That only one field is updated despite sending all the fields of the table in the Json (I think I have achieved it with my serializer).
And, where I have problems, is in disabling the creation of new records when updating one that does not exist.
I am using an UpdateAPIView to allow trying to allow a bulk update using a json like this (subrrogate_key is in my table and I use lookup_field to:
[
{
"subrrogate_key": "A1",
"class": "A"
},
{
"subrrogate_key": "A2",
"class": "B"
},
{
"subrrogate_key": "A3",
"class": "C"
},
]
When using the partial_update methods use update and this perform_update and this finally calls save and the default operation is to insert a new record if the primary key (or the one specified in lookup_field) is not found.
If I overwrite them, how can I make a new record not be inserted, and only update the field if it exists?
I tried:
Model.objects.filter (subrrogate_key = ['subrrogate_key']). Update (class = ['class])
Model.objects.update_or_create (...)
They work fine if all the keys in the Json exist, because if a new one comes they will insert (I don't want this).
P.S. I use a translator, sorry.
perform_update will create a new record if you passed a serializer that doesn't have an instance. Depending on how you wrote your view, you can simply check if there is an instance in the serializer before calling save in perform_update to prevent creating a new record:
def perform_update(self, serializer):
if not serializer.instance:
return
serializer.save()
Django implements that feature through the use of either force_update or update_fields during save().
https://docs.djangoproject.com/en/3.2/ref/models/instances/#forcing-an-insert-or-update
https://docs.djangoproject.com/en/3.2/ref/models/instances/#specifying-which-fields-to-save
https://docs.djangoproject.com/en/3.2/ref/models/instances/#saving-objects
In some rare circumstances, it’s necessary to be able to force the
save() method to perform an SQL INSERT and not fall back to doing an
UPDATE. Or vice-versa: update, if possible, but not insert a new row.
In these cases you can pass the force_insert=True or force_update=True
parameters to the save() method.
model_obj.save(force_update=True)
or
model_obj.save(update_fields=['field1', 'field2'])

Use attribute in unicode string in Django template

I have a model where I use a TextField() to store JSON data. Let say there is the following data in this field called json_data:
{"name":"alex","surname":"grs","type":"warrior"}
In my template I am trying to access attribute from my json_data object but without success (template thinks this json_data is a unicode string and not an iterable object.
{{json_data.name}} # empty
{{json_data.surname}} # empty
{{json_data}} # print {"name":"alex","surname":"grs","type":"warrior"}
Do you have an idea how I can access those attributes? I would like to transform it in a python object but I am not sure how to do that.
You just need to deserialize it, in the view.
json_data = json.loads(my_json_string)
You should probably consider using one of the many third-party JSONField implementations, which would take care of deserializing the data when you load the model and serializing it again when you save.

Getting Contents of `resource_uri` During Tastypie Hydrate

How can I resolve a resource_uri during a Tastypie hydrate call?
I am passing the following data object to a Tastypie resource:
{
'date': u'2013-10-31 15:06',
'visitor': u'/visitorlog/api/v1/person/33/',
'purpose': u'Testing'
}
I would like to take the visitor and pull the entire record in a hydrate function, which populates a field with some extra information.
I am currently doing this by splitting out the id and performing a search:
def hydrate_meta(self, bundle):
'''
This will populate the `meta` field with a snapshot of the employee record, if the `empid` is set. This is done so if the employee record changes we retain certain information at the time of the visit.
'''
split_id = bundle.data['visitor'].split('/')
# the id of `visitor` is in `split_id[-2]
# get the record of this visitor from the Django model
person_record = Person.objects.get(pk = split_id[-2])
# ... snipped ... create the `meta_value` object
bundle.data['meta'] = meta_values
return bundle
This is working, but calling split on the resource_uri does not seem the most elegant way to do this.
Is there more effective way to pull a record given a resource_uri?
Resource.get_via_uri(url) (doc) might come in handy.

Django: How to access the model id's within an AJAX script?

I was wondering what is the correct approach,
Do I create HiddenInput fields in my ModelForm and from the
View I pass in the primaryKey for the models I am about to edit into
the hiddenInput fields and then grab those hiddenInput fields from
the AJAX script to use it like this?
item.load(
"/bookmark/save/" + hidden_input_field_1,
null,
function () {
$("#save-form").submit(bookmark_save);
}
);
Or is there is some more clever way of doing it and I have no idea?
Thanks
It depends upon how you want to implement.
The basic idea is to edit 1. you need to get the existing instance, 2. Save provided information into this object.
For #1 you can do it multiple ways, like passing ID or any other primary key like attribute in url like http://myserver/edit_object/1 , Or pass ID as hidden input then you have to do it through templates.
For #2, I think you would already know this. Do something like
inst = MyModel.objects.get(id=input_id) # input_id taken as per #1
myform = MyForm(request.POST, instance=inst)
if myform.is_valid():
saved_inst = myform.save()
I just asked in the django IRC room and it says:
since js isn't processed by the django template engine, this is not
possible.
Hence the id or the object passed in from django view can't be accessed within AJAX script.

How to serialize to json format a queryset that use the 'extra' statement in Django?

I want to serialize a QuerySet that contains an extra statement:
region_list = Region.objects.extra(select={ 'selected': 'case when id = %s then 1 else 0 end' % (new_region.id)}).all()
I use the statement below to serialize
return HttpResponse(serializers.serialize('json', region_list), mimetype='application/json')
But when I obtain the json results in the browser, only the fields of the Region model appears, the selected field dissapear.
How can I fix that?
One slightly longwinded solution would be to to dump the objects to JSON via django-piston's JSONEmitter class. When you register your Region model with piston, you can say what fields to include, and mention 'selected' there, and then use your annotation to make sure that the queryset used in the piston handler contains all the info you want.
Or just look at how piston does it and, if you don't want all of piston, just mimic the bits you do.