Populate model(database) with json data in django - json

I read about de/serializers but i couldn't find my way here. I have two apps, one where i store my data(scraped data) and another where i use the current/new data to display. I have identical models in these two apps. So i converted model of say app A to json and now i want to populate model of app B with that json . How might it be done? I didn't like to use django REST framework though.
so i did python manage.py dumpdata app_name > somefile.json
how do i populate fields of model B with the contents of somefile.json?

You can use model serializers. Lets say you have a model MyModel, create a serailizer for this model by,
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
You will have to create a list with each element in the list as a dictionary of MyModel instance data. JSON data in python is basically a dictionary. So each element in your list will be dictionary (JSON data) for each unique instance of your model.
The list might look like:
[
{
"pk": "1",
"field_1": "data_1",
"field_2": "data_2",
.....
},
{
"pk": "2",
"field_1": "data_1",
"field_2": "data_2",
.....
},
...
]
Now pass the list with json data for MyModel to the serializer. If the json data is valid the serializer will deserialize the data into MyModel instances. Then you can simply save them.
serializer = MyModelSerializer(data=json_data, many=True)
if serializer.is_valid():
serializer.save() # `.save()` will be called on each deserialized instance

Related

Ktor: How to serialize/deserialise JSON-API (vnd.api+json)

I'm looking to rewrite a spring javafx application in Kotlin using Ktor. I am new to both Spring and Ktor.
I'm having trouble using Ktor to figure out how to approach serialization and deserialisation of POJOs. (These POJOs are part of a common library).
The API I'm trying to serve requests to with Ktor uses:
Hibernate ORM as ORM mapper
Elide with RSQL filters to serve JSON-API conform data
For example "data/event" would return:
{
"data": [
{
"type": "event",
"id": "15b6c19a-6084-4e82-ada9-6c30e282191f",
"attributes": {
"imageUrl": null,
"name": "some text",
"type": "NUMERIC"
}
}, // and more event objects
]
}
Looking at the codebase in the spring application, it looks like they are using a RestTemplate to deserialise the above into an Event class (which only has an id, imageUrl, name and type as variables). Spring seems to automatically know how to get a POJO from JSON-API.
How can I do the same with Ktor? I tried the simplest:
val response = client.request<List<Event>>("data/event")
With the serialiser as gson:
install(JsonFeature) {
serializer = GsonSerializer()
}
But this results in a list of Event objects with none of their variables correctly set.
I have to make a wrapper class:
data class MyWrapper(val data: List<Event>)
And with that it will populate the list with the objects id set correctly, but none of the other attributes. So by default it looks like Ktor isnt configured for JSON-API. How can I change this?
I believe JSON:API is not supported out of the box. You need to write your own serializer, or use another wrapper class:
class JSONAPI<T>(val type: String, val id: String, val attributes: T)
data class MyWrapper(val data: List<JSONAPI<Event>>)
The problem here is that all fields in Event except of id will be filled. So you will need to adjust deserialization result:
val response: List<Event> = client.request<MyWrapper>("data/event").data.filterNotNull().map { it.attributes.copy(id = it.id) }

Expecting JSON object instead of JSON Array

In my django application with database engine djongo, I'm trying to return a JSON response by retrieving from my database. But, I'm receiving JSON array instead of JSON object. Currently, there is only one record in my database. Please see the code below.
model.py
class bloodDonors(models.Model):
location=models.CharField(max_length=20)
name=models.CharField(max_length=20)
phone=models.IntegerField()
address=models.TextField()
bloodGroup=models.CharField(max_length=5)
type=models.CharField(max_length=20)
def __str__(self):
return self.name
views.py
class bloodDonersView(viewsets.ModelViewSet):
queryset = bloodDonors.objects.all()
serializer_class = bloodDonorsSerializer
JSON Reponse:
[
{
"id": 3,
"location": "Delhi",
"name": "Tony",
"phone": 888,
"address": "South street",
"bloodGroup": "B+",
"type": "blood-donation"
}
]
But, actually I needed the response as given below:
{
"id": 3,
"location": "Delhi",
"name": "Tony",
"phone": 888,
"address": "South street",
"bloodGroup": "B+",
"type": "blood-donation"
}
It sounds like you are using the 'list' endpoint that retrieves all objects matching the queryset, but you want to be using the detail retrieve endpoint, where you just retrieve one object. The good news is that because you are using a Model viewset, you get a detail retrieve GET endpoint for free. All you have to do is pass in the pk of the object you want as part of the url and it will return only the single object you requested.
So if your url is currently:
/api/v1/blood-donors
you'd want to use the url:
/api/v1/blood-donors/3
to get just the single object you want (with pk=3). The GET endpoint with no /{PK} at the end is always going to return a list, even if there's only one object in your database, and if you add the pk to the url you will always only get one object back, the object that matches the pk you pass in.
Update to answer your question in the comment. The new method would look something like this:
class bloodDonersView(viewsets.ModelViewSet):
queryset = bloodDonors.objects.all()
serializer_class = bloodDonorsSerializer
#action(detail=False, methods=['get',], url_path='first')
def get_first_object(self, request):
object = bloodDonors.objects.first()
serializer = bloodDonorsSerializer(object, many=False)
return response.Response(serializer.data)
the url you would use is
api/v1/blood-donors/first
and you need to check the documentation about where to import response and the action decorator.

DRF: can you deserialize one JSON key:value pair into multiple fields

In my API I have a module, which collects JSON objects obtained via POST request. JSON objects I'm receiving look more or less like this:
{
"id": "bec7426d-c5c3-4341-9df2-a0b2c54ab8da",
"data": {
"temperature": -2.4,
// some other stuff is here as well ...
}
}
The problem is requirement that I have to save both: records from data dictionary and whole data dictionary as a JSONField. My ORM model looks like this:
class Report(BaseModel):
id = models.BigAutoField(primary_key=True)
data = JSONField(verbose_name=_("Data"), encoder=DjangoJSONEncoder, blank=True, null=True)
temperature = models.DecimalField(
max_digits=3,
decimal_places=1,
)
# other properties
Is there any neat way to get both properties in one attempt to deserialize JSON object? Currently I use nested serializers formed like this:
class DataSerializer(serializers.ModelSerializer):
temperature = serializers.DecimalField(
source="temperature", write_only=True, max_digits=3, decimal_places=1
)
class Meta:
model = Report
fields = ("temperature")
class ReportSerializer(serializers.ModelSerializer):
id = serializers.UUIDField(source="uuid", read_only=True)
data = DataSerializer(source="*")
class Meta:
model = Report
fields = ("id", "data")
which obviously does not pass whole data dictionary to validated_data, which means I have to update the JSON field elsewhere (not good since I would like to have both data and temperature at null=False in ORM model). Any good ideas on how to fix this using DRF serializers would be appreciated.
I believe you should be able to override validate method for your serializer where you can "store initial data JSON field" and do the default validation by calling super()... method.
More info https://www.django-rest-framework.org/api-guide/serializers/#validation
Also, there are object-level validation functions available, you can take a look there as well for the initial posted data
https://www.django-rest-framework.org/api-guide/serializers/#object-level-validation
Also, you can override the method run_validation to access the initially passed data object.

Decode resulting json and save into db - Django + Postgres

I have a model like this:
class MyClass(models.Model):
typea = models.CharField(max_length=128)
typeb = models.CharField(max_length=128)
If for example, the resulting json from an API is like this:
{
"count": 75,
"results": [
{
"typea": "This tipe",
"typeb": "A B type",
"jetsons": [],
"data": [
"https://myurl.com/api/data/2/",
],
"created": "2014-12-15T12:31:42.547000Z",
"edited": "2017-04-19T10:56:06.685592Z",
},
I need to parse this result and save typea and typeb into the database, I'm kind of confused on how to do this.
I mean, there is the JSONField on Django, but I don't think that will work for me, since I need to save some specific nested string of the json dict.
Any example or idea on how to achieve this?
I mean, my confusion is on how to parse this and "extract" the data I need for my specific fields.
Thank You
You can always do an import json and use json.load(json_file_handle) to create a dictionary and extract the values you need. All you need is to open the .json file (you can use with open("file.json", "r") as json_file_handle) and load the data.

Django serializers - add/update fields attribute value

I'm using Django serializer for serializing the model data into JSON.
For example:- I have a model(CHECKTYPE) that contains one field 'types'.
Now 'types' contains comma(,) separated items like 'test, test1, test2'.
I'm using Django serializer like below (somewhere in view.py):
gettypes = CHECKTYPE.objects.all()
mytypes = serializers.serialize("json", gettypes)
return HttpResponse(mytypes, content_type="application/json")
This returns me a JSON on web page like below:
[{"model": "porttype.CHECKTYPE", "pk": "xyz00000005", "fields": {"types": "test, test1, test2"}}]
Now here I want to manipulate the fields attributes before serializing the data.
For example: I want to add one more attribute in fields 'lasttype' which will be last index of the list if I split the 'types' by comma.
lasttype = types.split(',')[-1]
so final json response should look like this:
[{"model": "porttype.CHECKTYPE", "pk": "xyz00000005", "fields": {"types": "test, test1, test2", "lasttype":"test2"}}]
I tried to do this like below but it's not working:
gettypes = CHECKTYPE.objects.all()
updated_types = []
for mtype in gettypes:
mtype.lasttype = mtype.types.split(',')[-1]
updated_types.append(mtype)
mytypes = serializers.serialize("json", updated_types)
return HttpResponse(mytypes, content_type="application/json")
But this is not working. It's giving me same JSON response and not showing the 'lasttype' attribute.
Please let me know if there is any possibility to achieve this.
Thanks,
Shashank
The best way to modify the response you are sending is by loading the json to dict then modifying the dict, then again json dumps the data for the response.
Instead of modifying fields before serializing, you should modify the fields after serializing.
import json
mytypes = json.loads(serializers.serialize("json", gettypes))
updated_types = []
for mytype in mytypes:
last_type = mytype['fields']['types'].split(',')[-1]
mytype['fields']['lasttype'] = last_type
updated_types.append(mytype)
return JsonResponse(updated_types)
By using JsonResponse you can directly json data without re-serializing the dict or list.
The expected data should be like this:
'[{"pk": "xyz00000005", "model": "porttype.CHECKTYPE", "fields": {"lasttype": " test2", "types": "test, test1, test2"}}]'