Python ModelSerializer change name to start with "#" sign - python

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
:)

Related

Filter nested serializer model field (exclude particular field)

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]

How do you add existing objects to a ManyToMany field using Serializer?

I am trying to create an API with Artists and Songs, with a ManyToMany relationship between the two. Using the API to create a Song with an Artist that is not in the database works fine. The problem arises when I attempt to use the POST method to create a new Song with an Artist that already exists in the database. I tried overwriting the SongSerializer create() method using get_or_create() based on another post here, but I kept getting Bad Request errors when the Artist already exists in the database. The relevant code snippets:
models.py
class Artist(models.Model):
artist_name = models.CharField(max_length=200, unique=True)
class Meta:
ordering = ['artist_name']
def __str__(self):
return self.artist_name
class Song(models.Model):
song_title = models.CharField(max_length=200)
artists = models.ManyToManyField(Artist, related_name='songs')
class Meta:
ordering = ['song_title']
def __str__(self):
return self.song_title
serializers.py
class ArtistNameSerializer(serializers.ModelSerializer):
class Meta:
model = Artist
fields = ('artist_name',)
def to_representation(self, value):
return value.artist_name
class SongTitleSerializer(serializers.ModelSerializer):
songs = serializers.PrimaryKeyRelatedField(read_only=True, many=True)
def to_representation(self, value):
return value.song_title
class Meta:
model = Song
fields = ('songs',)
class ArtistSerializer(serializers.HyperlinkedModelSerializer):
songs = SongTitleSerializer(read_only=True, many=True)
class Meta:
model = Artist
fields = ('id', 'artist_name', 'songs')
class SongSerializer(serializers.HyperlinkedModelSerializer):
artists = ArtistNameSerializer(many=True)
class Meta:
model = Song
fields = ('id', 'song_title', 'artists',)
def create(self, validated_data):
artist_data = validated_data.pop('artists')
song = Song.objects.create(**validated_data)
song.save()
for artist_item in artist_data:
a, created = Artist.objects.get_or_create(artist_name=artist_item['artist_name'])
song.artists.add(a)
return song
I've done some tests and it looks like the program doesn't even go into the create() method I'm using, going straight to showing me the Bad Request error. What am I missing? Thanks in advance!
On you Artist model you have a constrain on the artist_model field (unique=True)
if you print the serializer in question with:
print(SongSerializer())
you get something like this:
SongSerializer():
id = IntegerField(label='ID', read_only=True)
song_title = CharField(max_length=200)
artists = ArtistNameSerializer(many=True):
artist_name = CharField(max_length=200, validators=[<UniqueValidator(queryset=Artist.objects.all())>])
under the artist_name field is a Validator "UniqueValidator"
so in case of a write operation you can disable the validator in the serializer with:
class ArtistNameSerializer(serializers.ModelSerializer):
class Meta:
model = models.Artist
fields = ('artist_name',)
extra_kwargs = {
'artist_name': {
'validators': [],
}
}
hope this help..

Can I add the Model function property in the API?

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

How to return several list without the model in Rest Framework?

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)

Django Serializer Display Model Field as Dictionary

I apologize, new to Django. I've been scouring the documentation and haven't been able to find the answer to this.
I have a model "Foo" that has a field "bar", which is a dictionary I store as JSON in a TextField. I want a GET request to display this field as a dictionary, but when I make the request, the dictionary is displayed as a single string in JSON format.
To summarize my code:
models:
class Foo(models.Model):
bar = models.TextField(blank=True, default="{}")
def getBar(self):
return json.loads(bar)
Serializers:
class FooSerializer(serializers.ModelSerializer):
class Meta:
model = Foo
fields = ("bar")
read_only_fields = ("bar")
def create(self, data):
return Foo.objects.create(**data)
views:
class FooList(generics.ListAPIView):
queryset = []
for foo in Foo.objects.all():
foo.bar = json.loads(foo.bar)
# Printing type of foo.bar here gives "type <dict>"
queryset.append(foo)
serializer_class = FooSerializer
Thanks!
You can add a SerializerMethodField to your ModelSerializer class like below:
class FooSerializer(serializers.ModelSerializer):
class Meta:
model = Foo
fields = ('bar',)
read_only_fields = ('bar',) # Not required, because
# SerializerMethodField is read-only already
bar = serializers.SerializerMethodField('get_bar_dict')
def get_bar_dict(self, obj):
return json.loads(obj.bar) # This gets the dict and returns it
# to the SerializerMethodField above
# Below is the rest of your code that I didn't touch
def create(self, data):
return Foo.objects.create(**data)

Categories

Resources