How do I encode a UUID to make it JSON serializable - django-rest-framework

I am using UUID instead of the default Django incremental IDs. However, now I get the following error:
file "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py",
line 184, in default
raise TypeError(repr(o) + " is not JSON serializable") TypeError: UUID('4fd5a26b452b4f62991d76488c71a554') is not JSON serializable
Here is my serializer file:
class ApplicationSerializer(serializers.ModelSerializer):
class Meta:
model = Application
fields = ("id", "created_at", "merchant_uri", "api_key",
"status", 'owner_email', 'business_type', 'full_name',
'owner_phone_number', 'marketplace_name', 'domain_url',
'support_email', 'support_phone_number', 'postal_code',
'street_address', 'current_processor',
'current_monthly_volume')

This usually means you need to force your UUID to be serialized as a string, which can be done with the CharField. Some UUID field implementations for Django will do this by default, but it appears as though the one you are using will return the raw UUID object. By setting the field to a CharField, this will force it to be converted to a string.
class ApplicationSerializer(serializers.ModelSerializer):
id = serializers.CharField(read_only=True)
class Meta:
model = Application
fields = ("id", "created_at", "merchant_uri", "api_key",
"status", 'owner_email', 'business_type', 'full_name',
'owner_phone_number', 'marketplace_name', 'domain_url',
'support_email', 'support_phone_number', 'postal_code',
'street_address', 'current_processor',
'current_monthly_volume')
This will convert it to a string manually and will give you the output you are expecting.

You can use django-uuidfield, it serializes automatically.

Related

best way to add new properties to a model when using spring boot with mongodb

I'm looking for a better way to change a model with Spring + Mongodb, currently every time a property is added to a model, we have to create a command to be ran in mongosh to add that field to all documents, and then save it so that it can be ran on every environment that the new model is pushed to.
So for example, lets say a Event object has the properties:
#Document
data class Device(
#Id
val id: String? = null,
#Indexed(unique = true)
val name: String,
var location: String,
)
And we want to add a field "date": 2023-02-02T20:10:19.111Z to it. Currently I will have to create a mongosh command to update all events on the collection to add that field, so something like this:
db.device.updateMany({}, {$set: {'date': new Date().toISOString()}})
We then save this, and remember to run it every single time we merge to a upstream branch.
Is there a better way to define a new model with the date, so that it can create the field automatically?
I would add the new property with a default value, but everyone usecase/trade-offs is different.
#Document
data class Device(
#Id
val id: String? = null,
#Indexed(unique = true)
val name: String,
var location: String,
val newProperty:String? = null
)
This will allow you to get values don't exist in the database as null

Django Rest Framework - writable HyperlinkedRelatedField

So, I have a HyperLinkedModelSerializer that creates a like on the post.
And I need to pass post_id with POST-request.
But the problem is HyperlinkedRelatedField can't build a URL on the post field.
The veiw_name is correct.
If I try to change HyperlinkedRelatedField to PrimaryKeyRelatedField - it works perfectly.
Any ideas why so?
p.s. I figured that I pass post_id as a string, e.g. 145, but the serializer waits for the URL.
But which way can I transform imputed post_id into a URL?
Use get_absolute_url? But how to transform it in serializer or view?
class LikeDetailSerializer(serializers.HyperlinkedModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name="like-detail-api")
user = serializers.HyperlinkedRelatedField(
read_only=True, source="user.id", view_name="user-detail-update-destroy-api"
)
post = serializers.HyperlinkedRelatedField(
queryset=Post.objects.all(), view_name="post-detail-api",
)
class Meta:
model = Like
fields = "url", "id", "created", "user", "post"

How to use same serializer for different request?

Suppose I have a VehicleSerializer
class VehicleSerializer(serializers.Serializer):
person = PersonSerializer()
class Meta:
model = Vehicle
fields = ('id', 'type', 'person')
I need to use this serializer for get as well as post api. For get request this should be same, but for post request, i need to send data like:
{
"type": "Car",
"person": 1 (the id of the person row)
}
How can i use same Vehicle Serializer to validate this request too? As the above serializer will take only the dict value for person key.
Any help will be appreciated.
I think you need to set the person_id field for writing.
class VehicleSerializer(serializers.ModelSerializer):
person = PersonSerializer(read_only = True)
person_id = serializers.IntegerField(write_only = True)
class Meta:
model = Vehicle
fields = ('id', 'type', 'person', 'person_id')

drf-spectacular: how to show the primary key in examples section of Swagger

I'm trying to show the primary key in the examples section of Swagger, I'm using drf-spectacular and my code looks like:
Serializers.py
class SerializerExample(serializers.ModelSerializer):
class Meta:
model = Book
fields = ('id','name')
Views.py
class BooksBulkUpdate(APIView):
#extend_schema(
request=SerializerExample(many=True),
responses={200:''},
)
def put(self, request, format=None):
with transaction.atomic():
for data in request.data:
book = Book.objects.get(pk=data['id'])
serializer = SerializerExample(book, data=data, partial=True)
if serializer.is_valid():
serializer.save()
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
return Response()
Only the name field is showing:
The only solution that I found was using an inline serializer which is not the ideal solution because if I update my book serializer I'd have to remember to update also this inline serializer. I wonder if there is a better way of doing this.
AFAIK swagger shows input request schema.
For example, you want to add new person and your model is
class Person(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
name = models.CharField(max_length=30)
So you allowed to set only name parameter
Even if you post
{
"id": "someUUID",
"name": "NAME",
}
id will be ignored and Django create it automatically by own logic (because it is read only)
But you can set id field writeable:
class SerializerExample(serializers.ModelSerializer):
id = serializers.UUIDField(write_only=True)
name = serializers.CharField(write_only=True)
class Meta:
model = Person
fields = ('id','name')
write_only=True means that field will be active when you saving new data and receiving id from request json.
In opposite read_only=True will print id field at response (if you trying get data) but ignore it when you saving new data.
So you try to describe API for data adding, and of course that is not allow to set id field in request json.
Not sure if this theory applicable to your case, but hope that will be helpful.

Spring/Kotlin: How do I make a missing JSON field deserialize to the default value given by my entity class, and not to null?

I have an entity, defined using a data class:
#Entity
data class BlogPost(
(...)
val title: String,
(...)
val slug: String = title.toSlug(),
)
As per this answer, I expected that a JSON object without a slug field would deserialize to a BlogPost whose slug was created using my .toSlug() extension method – but, to my surprise, the deserialized .slug ends up being null even though I thought it wasn't nullable (it's a String, not a String?).
I've tried using #JsonInclude(Include.NON_NULL), but I suspect this is the wrong tactic, and it only seems to affect serialization; the missing JSON value is still deserialized to null rather than my default.
I'm on Spring Boot 2.4.3.

Resources