Django Rest Framework ModelSerializer create if not exists - python

I'm using Django Rest Framework 3.6.3. I'm trying to write nested create serializers for one optional argument and one required argument inside a child. I know that I need to override create in the base serializer to tell DRF how to create the nested children - http://www.django-rest-framework.org/api-guide/relations/#writable-nested-serializers.
However, I can't figure out how to get it to parse the object information without telling it what the nested child serializer is defined as. Doing that then causes DRF to use it to parse the children objects, which then returns a validation error that I have no control over because the child serializer doesn't call its create method.
Base
Specification(many=True)
OptionalField
RequiredField
The information I pass in is a JSON object:
{
base_id: 1,
base_info: 'blah'
specifications: [
{
specification_id: 1,
optional_info: {
optional_id: 1,
optional_stuff: 'blah'
},
required_info: {
required_id: 1,
required_stuff: 'required',
}
}
]
}
The BaseCreationSerializer calls it's create method. I know that I need to pull out the rest of the information and create it manually. However, I can't figure out how to get the BaseCreationSerializer to parse the data into validated_data without defining specification = SpecificationCreationSerializer(), which then tries to parse that and throws an error. Printing self shows the entire JSON object in data, but then validated_data only contains the subset of things that the serializer knows about. How do I parse the appropriate things from data so that I can create the objects on my own?

Related

On The Fly Validating and Manipulating Dictionary by Django-Rest Serializer (NO MODEL)

I have some data (dict) and I want to validate its data structure at the first and ensure about validation, after that I want to change fields name (CamelCase to snake_case), that's all it!
I had lots of searches and I know about re_presentation method (it seems it calls only when using ModelSerializer as a parent class) and also read about ListSerializer.
Any helps will be appreciated :)
This is the possible way to do this
Assume you have a payload like this
{
'data':{
},
'serializer_class': 'user_profile'
}
Now you will load the serializer byserializer_class token from project path. Please see this
serializer_classes = {
'user_profile': 'path.to.user_profile.serilizer'
}
Once you will load the serilizer as module you can pass the data to the serializer and perform validation on data.
After validation you can play further with your validated data.

Django validate a python dictionary via DictField

I'm new to the django rest framework and have two basic questions about something I don't fully understand. I have a python function which takes as an input a dictionary and would like to make it available via an API.
In [24]: def f(d):
...: pass
...:
I'm testing a post request via postman sending a json file which should be translated to my python dictionary. The input I'm sending looks like
{
"test": {
"name1": {
"list": ["a",
"b",
"c"
],
"numbers": [0.0, 0.1]
}
}
}
As you can see this is a dict currently with one key name1 which itself is a dict with two keys, list and numbers.
The view set I wrote for this example looks like this:
class TestViewSet(viewsets.ViewSet):
def create(self, request):
serializer = TestSerializer(data=request.data)
print(type(request.data.get("test")))
if serializer.is_valid():
print(serializer.validated_data.get("test"))
f(serializer.validated_data.get("test"))
and my serializer looks like this:
class TestSerializer(serializers.Serializer):
test = serializers.DictField()
If I send the json input above I get the printed the following:
<type 'dict'>
None
So I have the following two questions:
As we can see the request.data.get("test") is already the desired type (dict). Why do we want to call the serializer and doing some validation. This might cast certain inputs to not standard python types. E.g. validating a decimal via the DecimalField returns a object of type Decimal which is a Django type not a standard python type. Do I need to recast this after calling the serializer or how do I know that this won't cause any trouble with function expecting for example native python float64 type?
How can I define the serializer in the above example for the dictionary so that I get returned the correct object and not None? This dictionary consists of a dictionary consisting of two keys, where one value is a list of decimals and the other a list of strings. How can I write a validation for this within the DictField?

How to return primitive data types in a Django Rest Framework response (and not a UUID)

I'd like to know how to return primitive data types in a response in Django Rest Framework,(especially for UUID's, to return them as a string).
I have this code:
class TicketCreateSerializer(BaseCreateSerializer):
class Meta:
model = Ticket
fields = TICKET_FIELDS
def to_representation(self, obj):
obj = super(TicketCreateSerializer, self).to_representation(obj)
return dict(obj)
It is returning:
{
'requester': UUID('e1ba1b8b-5d9b-473e-947b-971d795e9137'),
'attachments': [],
'assignee': UUID('f584c3cb-2c9d-4a26-8e59-1dd343839606'),
'id': '00aa5549-f701-4b7e-82a5-5b2ac48c96ae',
'location': UUID('9f9e5b8d-b156-47d9-98fc-bbec10788040'),
'status': UUID('8a7edad5-19bb-4708-8d50-58a516749734'),
'cc': [UUID('e8fb8a4b-d79c-4601-b31e-5abdbe8dbfee')],
'priority': UUID('3f3ba388-6652-4744-9804-5d7e041cee7f'),
'request': 'new request name',
'categories': [UUID('c88f3e94-3d35-4816-80fb-6188fa6ec280')]
}
Instead of UUID data types for the ID's, is there a simple built in way to return strings of the ID's instead? To do this in Django Rest Framework?
Basically, how to return primitive python data types?
I feel like I've solved this issue in the past, but can't remember how...
The DRF serialization is a 2-step process.
The object is converted into a dict by a serializer, with simple types.
The dict is given to a renderer to generate a document.
The exact definition of “simple types” is a bit blurry. Basically, it is “whatever the renderers accepts”. For the JSONRenderer, that means:
all basic python types
datetime.datetime / datetime.date / datetime.time / datetime.timedelta
decimal.Decimal
uuid.UUID
QuerySet
Numpy arrays and array scalars
Any dict-like or sequence-like object.
Usually, you will only deal with step 1, as step 2 is automatically handled by DRF's Response. DRF automatically selects a rendered based on the view's renderer_classes setting and the request's Accept header.
Doing step 2 manually
You would do this if you need to generate a document (for instance a JSON document) yourself for some reason, for instance for tests. All you need is invoke the renderer yourself:
from rest_framwork.renderers import JSONRenderer
json = JSONRenderer().render(serializer.data)
That gets you a whole json document as a bytestring. This is an atomic process though, it's whole document or nothing.
You could imagine creating a custom renderer that returns a dict with only string values, but that's way overkill for your purpose.

Convert Django queryset to dictionnary in a JSON serialization purpose

I'm creating an API and I need to return data in a dictionnary format sothat it can be serialized (by the API mechanism).
The code that currently works is something as simple as:
def mymethod(self):
queryset1 = MyClass.objects.get(...) # Ccontains 1 object, easy to deal with
queryset2 = OtherClass.objects.filter(...) # Contains N objects, hard to deal with !
return {
'qs1_result': queryset1.some_attribute # This works well
}
Returning data from queryset1 is easy because there is 1 object. I just pick the attribute I need and it works. Now let's say that in addition, I want to return data from queryset2, where there are many objects, and that I don't need every attributes of the object.
How would you do that?
I repeat that I do NOT need to make the serialization myself. I just need to return structured data sothat the serialization can be made.
Thanks a lot.
From the Django docs: https://docs.djangoproject.com/en/dev/topics/serialization/#subset-of-fields
Subset of fields
If you only want a subset of fields to be serialized, you can specify a fields argument to the serializer:
from django.core import serializers
data = serializers.serialize('json', SomeModel.objects.all(), fields=('name','size'))
In this example, only the name and size attributes of each model will be serialized.

Subclassing python dictionaries

I am using ElasticSearch in my Python application and want to be able to create a reusable dictionary object that represents a query. The JSON structures are described here http://pulkitsinghal.blogspot.co.uk/2012/02/how-to-use-elasticsearch-query-dsl.html and I am using PyES to query the search server. With PyES we can pass a dict object which gets jsonified before sending to the server. I want to create a library of common queries where only the actual query term changes, so I thought I would subclass dict so I could pass in the query term via the constructor, for example, and when the dict gets jsonified I would end up with something like this:
{
"fields": [
"name",
"shortDescription",
"longDescription"
],
"query": {
"query_string": {
"fields": [
"name"
],
"query": query_term,
"use_dis_max": true
}
}
}
How would I do this? Is it true that only instance members get returned via __dict__ if so would I have to set up this data structure in the constructor? Is this the best way of doing this or should I create a class that does not extend dict and just create a to_dict() method that returns a dictionary in the correct structure?
Answer:
This seems to work fine, any suggestions for making this more 'pythonic' will be appreciated! (Yes I know there are no doc strings)
class StandardQuery(object):
search_fields = ['meta_keywords', 'meta_description', \
'fields.title.value', 'slug']
return_fields = ['slug', 'fields.title.value']
def __init__(self, query):
self.query = query
def to_dict(self):
output = dict()
output['fields'] = self.search_fields
output['query'] = {'query_string': {'fields': self.return_fields, \
'query': self.query, 'use_dis_max': True}}
return output
If you don't want all of the normal dict behaviour then you should definitely just create a separate class. You can then either give it a to_dict() method, or better since you really want to convert to json create a custom json encoder (and if required decoder) to use with the default argument of json.dumps().
In json.dump() and json.dumps() the optional argument default is a callable that should either return a serialized version of the object or raise TypeError (to get the default behaviour).

Categories