I am having difficulty serializing a django object. The problem is that there are foreign keys. I want the serialization to have data from the referenced object, not just the index.
For example, I would like the sponsor data field to say "sponsor.last_name, sponsor.first_name" rather than "13".
How can I fix my serialization?
json data:
{"totalCount":"2","activities":[{"pk": 1, "model": "app.activity", "fields": {"activity_date": "2010-12-20", "description": "my activity", "sponsor": 13, "location": 1, ....
model code:
class Activity(models.Model):
activity_date = models.DateField()
description = models.CharField(max_length=200)
sponsor = models.ForeignKey(Sponsor)
location = models.ForeignKey(Location)
class Sponsor(models.Model):
last_name = models.CharField(max_length=20)
first_name= models.CharField(max_length=20)
specialty = models.CharField(max_length=100)
class Location(models.Model):
location_num = models.IntegerField(primary_key=True)
location_name = models.CharField(max_length=100)
def activityJSON(request):
activities = Activity.objects.all()
total = activities.count()
activities_json = serializers.serialize("json", activities)
data = "{\"totalCount\":\"%s\",\"activities\":%s}" % (total, activities_json)
return HttpResponse(data, mimetype="application/json")
Add relations to the serializer like this:
activities_json = serializers.serialize("json", activities, relations=('sponsor',))
Then all you need is:
return HttpResponse(activities_json, mimetype="application/json")
Then make sure you also have the django library wadofstuff installed.
Hope this helps!
The docs seem to explain exactly how to do this. Read the part about serialization of natural keys.
This small lib is very handy with django : http://code.google.com/p/wadofstuff/wiki/DjangoFullSerializers
It allows more customisation than the standard encoder.
any2any also contains serializers allowing to customize completely the output format :
check the docs
repo on bitbucket
or on pypi
Related
I have a task to create a simple post API to send a visitor messages through a contact form that contain fields like full_name,address,phone etc. But instead of creating a model, I have to use an already existing model which has a Jsonfield. Now what I need to do is to use that jsonfield which will have all the fields like name, address etc.
class Core(models.Model):
"""
Model that saves the corresponding credentials for the slug.
"""
slug = models.CharField(max_length=255, null=False)
example = models.JSONField(null=False, default=dict)
def __str__(self) -> str:
return self.slug
If it was done in a regular way by creating a model, it would have been like this.
class Contacts(models.Model):
full_name = models.CharField(max_length=100,blank=True,default="")
email = models.EmailField()
phone = models.CharField(max_length= 16)
address = models.CharField(max_length=255,blank=True,default="")
message = RichTextField()
def __str__(self):
return self.email
Now, how should I send these fields data in a dictionary without in that JsonField without creating a Contacts model?
First of all, this question is not clear. Please ask your question in a clearer way. I hope the way below helps you.
This field keeps data like;
{"full_name":"John Doe", "email": "johndoe#doe.com", "phone":"XXXXXXXXXXX"}
You may create dictionary and assign to field. Also you may create json data like this;
json_example = json.dumps(full_name="John Doe, email="johndoe#doe.com, phone="XXXXXXXXXXX")
and then create a Core object ;
core = Core(example = json_example)
core.save()
Hello Stackoverflowers!
I've searched for a solution for this for a while, but have not been able to find anything addressing this usecase specifically.
Say we have the following models:
class Machine(models.model):
machine_name = models.CharField(max_length=30)
machine_data_template = models.JSONField()
class Event(models.model):
machine_name = models.ForeignKey(Machine, on_delete=models.CASCADE
machine_data = models.JSONField()
We have a machine for which there can be multiple events, the details of which are stored as JSON in a JSONField. The JSONField in event should be validated using the json-schema defined in Machine.machine_data_template.
I've looked at various Python/Django implementations of json-schemas, however I have not been able to find a way where we can define custom validation on a per-object basis. For example, solutions such as the one presented by Corwin Cole here defines the validation logic directly in the model, which would mean each instance of event would be subject to the same validation logic regardless of the machine:
MY_JSON_FIELD_SCHEMA = {
'schema': 'http://json-schema.org/draft-07/schema#',
'type': 'object',
'properties': {
'my_key': {
'type': 'string'
}
},
'required': ['my_key']
}
class MyModel(models.Model):
my_json_field = JSONField(
default=dict,
validators=[JSONSchemaValidator(limit_value=MY_JSON_FIELD_SCHEMA)]
)
Does anyone have any suggestion how I can achieve the desired "fully polymorphic" behavior?
BR - K
You can override the Model.clean() method and add custom validation there. You have access to the Event and it's related Machine so can access the schema. Add an example using jsonschema similar to the linked answer
import jsonschema
class Machine(models.Model):
machine_name = models.CharField(max_length=30)
machine_data_template = models.JSONField()
class Event(models.Model):
machine_name = models.ForeignKey(Machine, on_delete=models.CASCADE)
machine_data = models.JSONField()
def clean(self):
try:
jsonschema.validate(self.machine_data, self.machine_name.machine_data_template)
except jsonschema.exceptions.ValidationError as e:
raise ValidationError({'machine_data': str(e)})
Suppose that I have models like these:
models.py
class Category(models.Model):
name = models.CharField(max_length=70, verbose_name='Name')
order_num = models.IntegerField(verbose_name='Order Number')
class Advertisement_Type(models.Model):
name = models.CharField(max_length=70, verbose_name='Name')
ad_category = models.ManyToManyField(Category, verbose_name='Ad Category')
class Advertisement(models.Model):
title = models.CharField(max_length=70, verbose_name='Title')
ad_type = models.ForeignKey(Advertisement_Type, on_delete=models.CASCADE, verbose_name='Advertisement Type')
How can I retrieve advertisement by category and advertisement type in such format by using filters only? Is this possible? Because the only way I can think of is querying everything and then building the dictionary/JSON manually through a number of for-loops and if-else which I would like to avoid.
Expected format/output
advertisement_type: {
name: 'Type 1',
category: {'Health', 'Engineering'},
advertisement: {ads1, ads2, ads3}, # Can these be objects?
},
advertisement_type: {
name: 'Type 2',
category: {'Math', 'Numbers'},
advertisement: {ads4, ads5, ads6}, # Can these be objects?
}
Thank you!
To get related objects of a model you can use prefetch_related which can work with ManyToMany relations.
In the example ads_types, ad_category, advertisement_set are QuerySets, so they return a list of objects and can be filtered as well.
ads_types = Advertisement_Type.objects.prefetch_related('ad_category', 'advertisement_set')
res = []
for adt in ads_type:
res.append({
"name": adt.name,
"category": adt.ad_category.values_list('name', flat=True),
"advertisement": adt.advertisement_set.values_list('title', flat=True),
})
Or you can check Django Rest Framework serializers for related objects to get json object representation along with relations.
You might also improve ManyToMany field by adding related_name option.
I've got some problems to understand the right way serializing data with django-rest-framework e.g. using data from related models.
Let me explain a little bit my situation:
I have an Organization model with a manytomany relation to a Subtopic model classifying each organiaztion. Further each subtopic belongs to a general topic.
In addition there is an OrgaDataSet model to save crawled data for each organization in a PostgreSQL JSONField. The field "type" in the OrgaDataSet Model should give me a kind of flexibility to classify crawled data in further stages.
# models.py
class Topic(models.Model):
name = models.CharField(max_length=200, unique=True)
class Subtopic(models.Model):
name = models.CharField(max_length=100, unique=True)
topic = models.ForeignKey(Topic, on_delete=models.CASCADE)
class Organization(models.Model):
name = models.CharField(max_length=300, unique=True)
description = models.TextField(blank=True, null=True)
subtopics = models.ManyToManyField(Subtopic)
class OrgaDataSet(models.Model):
data_set_types = (
('ADDRESS', 'address'),
('PERSON', 'person'),
('DIVISION', 'division'),
)
organization = models.ForeignKey(Organization, on_delete=models.CASCADE)
type = models.CharField(max_length=20, choices=data_set_types)
crawled_data = JSONField(verbose_name='Data set')
But lets come up with my questions / problems:
1. How can I serialize the related data with minimized database requests and get an customized serialized field like:
"topics_list": [
{
"topic_name": "Medical science",
"subtopics": [
"Dental products",
"Hygiene"
]
},
{
"topic_name": "Biotechnology",
"subtopics": [
"Microbiology"
]
}
],
I tried different approaches: amongst others a custom model manager to add a method "get_topics_list", however I'm sticking with the right way to query with "prefetch_related" and "select_related" ... But is this even the richt way?
Also I tried to set up a serializedMethodField in the serializer itself. However I was asking myself what is the best place to do the related query, in the view.py or in the serializers.py?
My second question concerns the OrgaDataSet model. I am absolutly uncertain how and where to place the queries, one for each "type". Should I do a specific method in the custom model manager for each type, like "get_type_address"?
I would appreciate your ideas and any hint to understand the utilization of the django-framework a little bit more.
Thanks a lot,
Mike
Question 1)
This is typical Category/Subcategory problem. I would suggest to look at the following django package : https://github.com/django-mptt/django-mptt
It would store Topics/Subtopics in one table ( tree structure ), making the queries efficient and you can easily produce the desired output efficiently
Question 2)
This depends how you want to display the data. Do you have one endpoint for each type ?
If you have one endpoint for each type, you can do a view like this :
class OrgaDataSetListView(generics.ListAPIView):
type = None
serializer_class =<your serializer>
def get_queryset(self):
return OrgaDataSet.objects.filter(type=self.type)
And use it like this in urls:
urlpatterns = [
path('orgadata/address', OrgaDataSetListView.as_view(type='ADDRESS')),
path('orgadata/person', OrgaDataSetListView.as_view(type='PERSON')),
]
I am creating an api end point using django-rest-framework for a specific json input. I have two related models like so (let's assume post can only have one category):
class Category(models.Model):
name = models.CharField(max_length=10)
slug = models.SlugField()
class Post(models.Model):
category = models.ForeignKey()
title = models.CharField(max_length=100)
text = models.CharField(max_length=256)
and my serializer are simple model serializers:
class CategorySerializer(ModelSerializer):
id = serializers.IntegerField(required=True)
class Meta:
model = Category
class PostSerializer(ModelSerializer):
id = serializers.IntegerField(required=True)
category = CategorySerializer()
class Meta:
model = Post
and my api view is very simple also:
class PostAPIView(mixins.CreateModelMixin, GenericAPIView):
serializer_class = PostSerializer
permission_classes = (IsAuthenticated,)
now in order to create posts I need to parse a json input like this:
{
"id": 10,
"pk": 10
"title": "Some title",
"text": "Some text",
"category": {
"id": 15,
"pk": 15
"name": "Best category",
"slug": "best-category"
}
}
in here 'pk' parameters are crucial for me, I want data to be created on my db using exact pk provided in json. Now if I make a post request and there are no posts with id:10 and categories with id:15 all is fine and data is written to db new records get inserted, but if there are any when rest-framework returns an error like ['Post id 10 already exists'], I would like matching records to be updated according to input instead. How can I do that?
You just need to add the UpdateMixin, just import it like the CreateModelMixin.
This mixin will implement the update and partial update methods, that will do what you want.
But you can not send a POST, for it you will need a PUT, or PATCH. You you want to do this on POST, I recommend you to implement your own create view method.