Can I add the Model function property in the API?
I have a Model:
class PhysicalServer(models.Model):
name = name = models.CharField(max_length=32)
trade_record = models.ForeignKey(to=TradeRecord, null=True, blank=True)
#property
def is_applied(self):
if self.trade_record == None:
return False
else:
return True
my PhysicalServerListAPIView of it:
class PhysicalServerListAPIView(ListAPIView):
serializer_class = PhysicalServerListSerializer
permission_classes = [AllowAny]
queryset = PhysicalServer.objects.all()
the PhysicalServerListSerializer:
class PhysicalServerListSerializer(ModelSerializer):
class Meta:
model = PhysicalServer
fields = "__all__"
I have a requirement, how can I add the is_applied to the list API?
I mean, if I access the ListAPI, the results data will be like:
{
name: xxx,
trade_record: xxx
},
...
How can I add this?
{
name: xxx,
trade_record: xxx
is_applied: xxx
},
...
just add the field description to the serializer
from rest_framework import serializers
class PhysicalServerListSerializer(ModelSerializer):
is_applied = serializers.BooleanField(read_only=True)
class Meta:
model = PhysicalServer
fields = "__all__"
I think the SerializerMethodField is what are you looking for.
Try this way.
class PhysicalServerListSerializer(ModelSerializer):
is_applied = serializers.SerializerMethodField()
class Meta:
model = PhysicalServer
fields = "__all__"
def get_is_applied(self, obj):
return self.trade_record is not None:
For more info: http://www.django-rest-framework.org/api-guide/fields/#serializermethodfield
Related
I am new to Django and I am trying to exclude a model field in nested serializer.
modals.py
class Blog(models.Model):
title = models.CharField(max_length=30)
description = models.CharField(max_length=30)
class Comment(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE, related_name="comment")
comment_bdy = models.CharField(max_length=30)
completed = models.BooleanField(default=False)
serializers.py
class BlogCommentSerializer(serializers.ModelSerializer):
class Meta:
model = Comment
fields = ("id", "comment_body")
class BlogSerializer(serializers.ModelSerializer):
comment = BlogCommentSerializer(many=True)
class Meta:
model = ("id", "title", "description", "comment",)
I am trying to exclude comment which have completed=True .
I have tried many times like :-
class BlogCommentSerializer(serializers.ModelSerializer):
def to_representation(self, data):
data = data.filter(completed=False)
return super(BlogCommentSerializer, self).to_representation(data)
But It showing:
AttributeError: 'CommentReply' object has no attribute 'filter'
Then I tried using:
class BlogSerializer(serializers.ModelSerializer):
def get_comment(self, instance):
comment_instance = instance.comment_set.exclude(completed=True)
return BlogSerializer(comment_instance , many=True).data
It also didn't work.
What I am trying to do
I am trying to exclude comments which are completed=True.
You can try like this using SerializerMethodField:
class BlogSerializer(serializers.ModelSerializer):
comment = serializers.SerializerMethodField()
def get_comment(self, instance):
comment_instances = instance.comment.exclude(completed=True)
return BlogCommentSerializer(comment_instances , many=True).data
Try it:
class BlogSerializer(serializers.ModelSerializer):
comment = serializers.SerializerMethodField()
def get_comment(self, obj):
queryset = Comment.objects.
filter(blog=obj).exclude(blog__completed=True)
return [BlogCommentSerializer(q).data for q in queryset]
I'm building an API with the django rest framework. I have these models:
class Organisme(models.Model):
nom = models.CharField(max_length=255)
adresse = models.ForeignKey(Adresse, on_delete=models.CASCADE)
class Adresse(models.Model):
rue = models.CharField(max_length=255, blank=True)
This is the view for my mode Organisme :
class OrganismeViewSet(viewsets.ModelViewSet):
queryset = Organisme.objects.all()
serializer_class = OrganismeSerializer
pagination_class = StandardResultsSetPagination
filter_backends = (filters.SearchFilter, DjangoFilterBackend)
filter_class = OrganismeFilter
search_fields = ('nom')
And my serializer:
class OrganismeSerializer(serializers.ModelSerializer):
class Meta:
model = Organisme
fields = '__all__'
depth = 1
So I'm trying to create a new Organisme by sending this:
{
"adresse": {
"rue": "test"
},
"nom":"TestTest",
}
or
{
"adresse": pk_id,
"nom":"TestTest",
}
But I always end up with this error:
IntegrityError at /organismes/
(1048, "Column 'adresse_id' cannot be null")
If you guys know how to proceed... Thank you in advance.
You need to override create method to make writable nested serializer:
class AddressSerializer(serializers.ModelSerializer):
class Meta:
model = Addresse
fields = ('rue',)
class OrganismeSerializer(serializers.ModelSerializer):
addresse = AddressSerializer()
class Meta:
model = Organisme
fields = '__all__'
def create(self, validated_data):
address_data = validated_data.pop('adresse')
address = Adresse.objects.create(**address_data)
organism = Organisme.objects.create(address=address, **validated_data)
return organism
How can I returns serval list in Rest Framework?
I have serializers.py
class HostTypeSerializer(ModelSerializer):
class Meta:
model = HostType
fields = "__all__"
class DiskOSTypeSerializer(ModelSerializer):
class Meta:
model = DiskOSType
fields = "__all__"
class DiskEssenceTypeSerializer(ModelSerializer):
class Meta:
model = DiskEssenceType
fields = "__all__"
I have the three Serializers, and I want to return data like bellow:
{
hosttypes:[the HostTypeSerializer's list data ],
diskostype:[the DiskOSTypeSerializer's list data],
diskessencetype:[the DiskEssenceTypeSerializer's list data],
}
I tried but failed, but I don't know how to do with that:
class DiskPreCreateSerialzer(ModelSerializer):
hosttypes = HostTypeSerializer(many=True, read_only=True)
diskostypes = DiskOSTypeSerializer(many=True, read_only=True)
diskessencetypes = DiskEssenceTypeSerializer(many=True, read_only=True)
class Meta:
fields = (
"hosttypes",
"diskostypes",
"diskessencetypes",
)
In views.py:
class DiskPreCreateAPIView(APIView):
serializer_class = DiskPreCreateSerialzer
permission_classes = []
...
I want to use this Serializer to returns my requirement, but failed, how can I get that?
EDIT
I don't know how to write my DiskPreCreateAPIView now, because I don't know how to get the data to return.
class DiskPreCreateAPIView(APIView):
serializer_class = DiskPreCreateSerialzer
permission_classes = []
def post(self, request):
return Response(data=xxx, status=HTTP_200_OK)
Try to use base Serializer instead of ModelSerializer:
class DiskPreCreateSerialzer(Serializer):
hosttypes = HostTypeSerializer(many=True, read_only=True)
diskostypes = DiskOSTypeSerializer(many=True, read_only=True)
diskessencetypes = DiskEssenceTypeSerializer(many=True, read_only=True)
And in your view pass dict with your lists to this serializer:
class DiskPreCreateAPIView(APIView):
serializer_class = DiskPreCreateSerialzer
permission_classes = []
def post(self, request):
...
serializer = self.serializer_class({
'hosttypes': hosttypes_qs,
'diskostype':diskostype_qs,
'diskessencetype': diskessencetype_qs,
})
return Response(data=serializer.data, status=HTTP_200_OK)
Python Model
class Foo(models.Model):
context = models.CharField()
Serializer
class FooSerializer(serializers.ModelSerializer):
class Meta:
model = Foo
fields = ("context")
View
class FooListView(generics.ListCreateAPIView):
queryset = Foo.objests.all()
serializer_class = FooSerializer
My structure is like above. And it produces the following Json as expected.
{
"context": "http://json-ld.org/contexts/person.jsonld"
}
Is it possible to add "#" sign at the beginning of the field?
Just replace your serializer with below code:
class FooSerializer(serializers.ModelSerializer):
class Meta:
model = Foo
fields = ("context", )
def to_representation(self, instance):
data = super(FooSerializer, self).to_representation(instance)
data["#context"] = instance.context
del data["context"]
return data
:)
I'm trying to replace one tested object another using PATCH request. For My experiments I use Postman. I send PATCH request with parameter user_status and value:
{"id": 1, "status_type": {"id": 2, "name": "new_status_type_name"},
"name": "new_status_name"}
I wrote update method for updating my ResultSerializer, but it doesn't work. Now I'm debuging it and I see that variable validated_data doesn't contain my new user_status. user_status is an empty OrderedDict:
ipdb> validated_data['user_status']
OrderedDict()
I checked my request and I see that user_status is a list with one element - string.
ipdb> self.context['request'].data
<QueryDict: {'user_status': ['{"id": 1, "status_type": {"id": 2, "name": "new_status_type_name"}, "name": "new_status_name"}']}>
How can I replace one another nested objects? Thank you for your help.
I have next Models:
class UserStatus(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(unique=True, max_length=255)
status_type = models.ForeignKey('StatusType', blank=True, null=True)
class Meta:
managed = False
db_table = 'user_status'
def __str__(self):
return self.name
class StatusType(models.Model):
id = models.SmallIntegerField(primary_key=True)
name = models.CharField(unique=True, max_length=256)
class Meta:
managed = False
db_table = 'status_type'
def __unicode__(self):
return self.name
class Result(models.Model):
id = models.BigIntegerField(primary_key=True)
user_status = models.ForeignKey('UserStatus', blank=True, null=True)
class Meta:
managed = False
db_table = 'result'
Serializers:
class UserStatusSerializer(serializers.ModelSerializer):
id = serializers.IntegerField()
name = serializers.CharField()
status_type = StatusTypeSerializer()
class Meta:
model = app.models.UserStatus
class StatusTypeSerializer(serializers.ModelSerializer):
id = serializers.IntegerField()
name = serializers.CharField()
class Meta:
model = app.models.StatusType
class ResultSerializer(serializers.ModelSerializer):
user_status = UserStatusSerializer(many=False)
def update(self, instance, validated_data, *args, **kwargs):
import ipdb; ipdb.set_trace()
instance.user_status = validated_data.get('user_status', instance.user_status)
instance.save()
return instance
class Meta:
model = app.models.Result
Views:
class StatusTypeViewSet(viewsets.ModelViewSet):
queryset = app.models.StatusType.objects.all()
serializer_class = app.serializers.StatusTypeSerializer
class UserStatusViewSet(viewsets.ModelViewSet):
queryset = app.models.UserStatus.objects.all()
serializer_class = app.serializers.UserStatusSerializer
class ResultViewSet(viewsets.ModelViewSet):
queryset = app.models.Result.objects.all()
serializer_class = app.serializers.ResultSerializer
After reading of this article Please. Don't Patch Like An Idiot.
I understood that I should use the list for patching, but Django REST doesn't want to use list, only objects. Ok, now I use next dict for pathcing:
{"op": "update", "field": "user_status_id", "new_value": 2}
and next code for sending this list:
import json
import requests
payload = json.dumps({"op": "update", "field": "user_status_id", "new_value": 2})
headers = {'content-type': "application/json"}
response = requests.patch(url, data=payload, headers=headers)
Then I changed serializers.py and views.py. I'll show you only main code without checking and other stufs :).
views.py (added the method perform_update):
class ResultViewSet(viewsets.ModelViewSet):
queryset = app.models.Result.objects.all()
serializer_class = app.serializers.ResultSerializer
def perform_update(self, serializer):
new_value = self.request.data.get('new_value')
user_status_ins = app.models.UserStatus.objects.get(id=new_value)
serializer.save(user_status=user_status_ins)
serializers.py (added the method update):
class ResultSerializer(serializers.ModelSerializer):
user_status = UserStatusSerializer(many=False)
def update(self, instance, validated_data, *args, **kwargs):
for field in validated_data.keys():
setattr(instance, field, validated_data.get(field))
instance.save()
return instance
class Meta:
model = app.models.Result
If you found better solution, please tell me.