I currently have a serializer with the following fields
class Meta:
model = Asset
fields = ('id', 'uuid', 'asset_category', 'asset_sub_category',
'make_label',
'asset_code', 'serial_number', 'model_number',
'checkin_status', 'created_at',
'last_modified', 'current_status', 'asset_type',
'allocation_history', 'specs', 'purchase_date',
'notes', 'assigned_to', 'asset_location'
)
Serializer
class AssetSerializer(serializers.ModelSerializer):
checkin_status = serializers.SerializerMethodField()
allocation_history = serializers.SerializerMethodField()
assigned_to = UserSerializer(read_only=True)
asset_category = serializers.SerializerMethodField()
asset_sub_category = serializers.SerializerMethodField()
make_label = serializers.SerializerMethodField()
asset_type = serializers.SerializerMethodField()
model_number = serializers.SlugRelatedField(
queryset=AssetModelNumber.objects.all(),
slug_field="model_number"
)
class Meta:
model = Asset
fields = ('id', 'uuid', 'asset_category', 'asset_sub_category',
'make_label',
'asset_code', 'serial_number', 'model_number',
'checkin_status', 'created_at',
'last_modified', 'current_status', 'asset_type',
'allocation_history', 'specs', 'purchase_date',
'notes', 'assigned_to', 'asset_location'
)
depth = 1
read_only_fields = ("uuid",)
View
class ManageAssetViewSet(ModelViewSet):
serializer_class = AssetSerializer
queryset = Asset.objects.all()
# permission_classes = [IsAuthenticated, IsAdminUser]
# authentication_classes = (FirebaseTokenAuthentication,)
http_method_names = ['get', 'post', 'put', 'delete']
filter_backends = (filters.DjangoFilterBackend,)
filterset_class = AssetFilter
def get_object(self):
queryset = Asset.objects.all()
obj = get_object_or_404(queryset, uuid=self.kwargs['pk'])
return obj
Model
Asset Model. Some fields have been ommited
class Asset(models.Model):
"""Stores all assets"""
uuid = models.UUIDField(unique=True, default=uuid.uuid4, editable=False)
asset_code = models.CharField(
unique=True, null=True, blank=True, max_length=50)
serial_number = models.CharField(
unique=True, null=True, blank=True, max_length=50)
created_at = models.DateTimeField(auto_now_add=True, editable=False)
asset_location = models.ForeignKey('AndelaCentre', blank=True, editable=True, null=True,
on_delete=models.PROTECT)
purchase_date = models.DateField(
validators=[validate_date],
null=True, blank=True)
last_modified = models.DateTimeField(auto_now=True, editable=False)
assigned_to = models.ForeignKey('AssetAssignee',
blank=True,
editable=False,
null=True,
on_delete=models.PROTECT)
model_number = models.ForeignKey(AssetModelNumber,
null=True,
on_delete=models.PROTECT)
current_status = models.CharField(editable=False, max_length=50)
notes = models.TextField(editable=False, default=" ", )
However, on the browsable Api, only 4 fields are showing on the UPDATE/PUT form as shown in the diagram below
What could be the reason some of the other fields are not appearing here. What determines which fields are updatable??
Well, the problem is when you set depth = 1 ModelSerializer tries to generate a NestedSerializer field for any foreignkey related field which you have not explicitly mentioned. And that NestedSerializer field is a read only field. That's why Assest Location is not being displayed. Remove that depth = 1 line and DRF will map the said field with the default mapping i.e. PrimaryKeyRelatedFiel and you will see that the said field is displayed.
In your model, you make editable=False for many fields. That fields won't display. If you want to display and edit that field remove that option.
For more info refer question
Related
This is my code for the hotel website
models.py
class Rooms(models.Model):
room = models.BigIntegerField(verbose_name='Комната', unique=True)
category = models.ForeignKey(Category, on_delete=models.CASCADE, verbose_name='Категория', related_name='wer')
room_bool = models.BooleanField(verbose_name='Статус', default=True)
price = models.BigIntegerField(verbose_name='Цена', null=True,blank=True)
class Registrations(models.Model):
room_num = models.ForeignKey(Rooms, on_delete=models.CASCADE, verbose_name='Номер', related_name='ertgdb',
limit_choices_to={'room_bool': True})
first_name = models.CharField(max_length=250, verbose_name='Имя')
last_name = models.CharField(max_length=250, verbose_name='Фамилия')
tel_num = models.BigIntegerField(verbose_name='Номер телефона')
img = models.FileField(verbose_name='Паспорт', null=True, blank=True)
visit_date = models.DateField(default=now, verbose_name='Дата прибытия')
leave_date = models.DateField(blank=True, null=True, help_text='Дата отбытия')
guest_count = models.IntegerField(default=1, verbose_name='Кол-во людей')
room_relevant = models.BooleanField(default=False, verbose_name='Статус')
price = models.BigIntegerField(verbose_name='Цена', default=100)
serializers.py
class RegistrationSer(serializers.ModelSerializer):
class Meta:
model = Registrations
fields = ('id', 'room_num', 'first_name', 'last_name', 'tel_num', 'img',
'visit_date', 'guest_count', 'room_relevant')
I need the room_num field (in the picture) to have not Id but room_num as in the Input form
SlugRelatedField doesn't work because I can't make POST PUT requests later
You can do the following:
class RegistrationSer(serializers.ModelSerializer):
room = serializers.CharField(source="room_num.room")
class Meta:
model = Registrations
fields = ('id', 'room', 'first_name', 'last_name', 'tel_num', 'img',
'visit_date', 'guest_count', 'room_relevant')
at my models.py I have a "Movies" model with the following field setup:
video_stream_relation = GenericRelation(VideoStreamInfo, related_query_name='video_stream_relation')
This GenericRelation field points to the following model class:
class VideoStreamInfo(models.Model):
objects = RandomManager()
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
content_type = models.ForeignKey(ContentType, limit_choices_to=referential_stream_models, on_delete=models.CASCADE, verbose_name=_("Content Type"))
object_id = models.CharField(max_length=36, verbose_name=_("Object ID"))
content_object = GenericForeignKey('content_type', 'object_id')
index = models.IntegerField(verbose_name=_("Stream Index"), blank=False)
bit_rate = models.IntegerField(verbose_name=_("Bitrate (bps)"), blank=True, null=True, editable=False)
codec_name = models.CharField(verbose_name=_("Codec Name"), blank=True, null=True, editable=False, max_length=255)
width = models.IntegerField(verbose_name=_("Width"), blank=True, null=True, editable=False)
height = models.IntegerField(verbose_name=_("Height"), blank=True, null=True, editable=False)
date_added = models.DateTimeField(auto_now_add=True, verbose_name=_("Date Added"))
Now the Question is how can I get video_stream_relation.codec_name value in a ModelSerializer like this:
class MovieSerializer(serializers.ModelSerializer):
id = serializers.PrimaryKeyRelatedField(queryset=Movies.objects.all())
class Meta:
model = Movies
fields = ('id',
...)
I want to be able to display the codec_name as a API JsonResponse.
If needed, this is how my API view currently looks like:
#api_view(['GET',])
#authentication_classes([JSONWebTokenAuthentication])
#permission_classes([AllowAny])
def movies(request):
if request.method == 'GET':
obj = Movies.objects.all()
serializer = MovieSerializer(obj, many=True)
return JsonResponse(serializer.data, safe=False)
If I try to add the video_stream_relation field to my MovieSerializer I get back the following error:
TypeError: Object of type GenericRelatedObjectManager is not JSON
serializable
Thanks in advance.
You can create a model serializer for VideoStreamInfo and use it in MovieSerializer as a related manager like this:
from rest_framework import serializers
class VideoStreamInfoSerializer(serializers.ModelSerializer):
class Meta:
model = VideoStreamInfo
fields = ('codec_name', )
class MovieSerializer(serializers.ModelSerializer):
video_stream_relation = VideoStreamInfoSerializer(many=True, read_only=True)
id = serializers.PrimaryKeyRelatedField(queryset=Movies.objects.all())
class Meta:
model = Movies
fields = ('id',
'video_stream_relation',
...
)
Here is my view
serializer_class = SceneSerializer
permission_classes = (permissions.IsAuthenticated,)
def get_queryset(self):
scene = Scene.objects.filter(user = self.request.user)
for s in scene:
test = Scene.objects.get(static_id = s.static_id)
lights = test.light.all()
temp = list(chain(scene, lights))
Here are my 2 serializers
class LightSerializer(serializers.ModelSerializer):
class Meta:
model = Light
fields = '__all__'
class SceneSerializer(serializers.ModelSerializer):
class Meta:
model = Scene
fields = '__all__'
Here is my models
class Light(models.Model):
static_id = models.AutoField(primary_key=True)
id = models.CharField(max_length=100, blank=True, null=True)
company = models.CharField(max_length=25, blank=True, null=True)
name = models.CharField(max_length=100, blank=True, null=True)
label = models.CharField(max_length=100, blank=True, null=True)
user = models.ForeignKey(User,on_delete=models.DO_NOTHING, related_name='userLights' )
def __str__(self):
return "{0} - {1}".format(self.user,self.static_id)
class Scene(models.Model):
static_id = models.AutoField(primary_key=True)
color = RGBColorField()
title = models.CharField(max_length=100, blank=True, null=True)
user = models.ForeignKey(User,on_delete=models.DO_NOTHING, related_name='userScenes' )
light = models.ManyToManyField(Light)
def __str__(self):
return "{0} - {1}".format(self.user,self.static_id)
Goal is to return the complete objects of the scene and the lights attached to each scene. the chain is working correctly but when I return the chain I am getting
You can include reverse relationships in serializers by adding the reverse relationship to fields
class SceneSerializer(serializers.ModelSerializer):
class Meta:
model = Scene
fields = ['light', 'static_id', 'color', 'title', 'user']
This will just return a list of ids, to serialize the related objects you can add the related serializer with many=True
class SceneSerializer(serializers.ModelSerializer):
light = LightSerializer(many=True)
class Meta:
model = Scene
fields = ['light', 'static_id', 'color', 'title', 'user']
I have the following object inheritance model.
class Room:
name = models.CharField(db_index=True, unique=True, max_length=255)
status = models.CharField(default=RoomStatus.ACTIVE, max_length=256, null=True)
members = models.ManyToManyField(User)
last_activity = models.DateTimeField(default=timezone.now)
And the inherited models are,
class LeagueRoom(Room):
league = models.ForeignKey(League, on_delete=models.CASCADE, null=True)
location = models.ForeignKey(Location, on_delete=models.CASCADE, null=True)
logo_url = models.CharField(max_length=1024, null=True)
and
class ClubRoom(Room):
club = models.ForeignKey(Club, on_delete=models.CASCADE, null=True)
location = models.ForeignKey(Location, on_delete=models.CASCADE, null=True)
logo_url = models.CharField(max_length=1024, null=True)
The respective Serializers are as follows,
class RoomSerializer(serializers.ModelSerializer):
members = UserSerializer(read_only=True, many=True)
class Meta:
model = Room
fields = ('id', 'name', 'status', 'members', 'created', 'modified', 'last_active')
and
class LeagueRoomSerializer(serializers.ModelSerializer):
location = LocationSerializer(read_only=True)
league = LeagueSerializer(read_only=True)
room = RoomSerializer(read_only=True)
class Meta:
model = LeagueRoom
fields = ('id', 'name', 'location', 'status', 'league',
'logo_url', 'room', 'created', 'modified',)
and
class ClubRoomSerializer(serializers.ModelSerializer):
location = LocationSerializer(read_only=True)
club = ClubSerializer(read_only=True)
room = RoomSerializer(read_only=True)
class Meta:
model = ClubRoom
fields = ('id', 'name', 'location', 'club', 'logo_url',
'status', 'room', 'created', 'modified',)
My problem is that I have fetched all rooms for an user in the following manner.
rooms = user.room_set.order_by('-last_activity')
Now I want to Serialize this data based on the room type. Thus instead of using the RoomSerializer I want to traverse the list of rooms and if the room is ClubRoom, then use ClubRoomSerializer or else LeagueRoomSerializer.
I'm not sure how to determine the child object from the parent.
Can someone help me with this.
class RoomSerializer(serializers.Serializer):
def to_representation(self, instance):
if isinstance(instance, LeagueRoom)
serializer_class = LeagueRoomSerializer
elif isinstance(instance, ClubRoom):
serializer_class = ClubRoomSerializer
return serializer_class(instance=instance).data
queryset = user.room_set.order_by('-last_activity')
serialized = RoomSerializer(queryset, many=True).data
I have 3 model Product - Peyment - ProductDiscountControll
Peyment and ProductDiscountControll have relation to column "product" to Product table
I want to have related ProductDiscountControll data like discount and discount_code_precent in peyment serilizer at get request.
In quest to do that, I tried following code in my Serializer Class
def get_product_discount(self, obj):
return obj.product.product_discount.discount
but server says :
Field name `product_discount` is not valid for model `Peyment`.
I also tried like this way:
product_discount = ProductDiscountControllSerializer(many=True,read_only=True)
but product_discount not available in result
my view is look like this
class PeymentAPIView(APIView, mixins.DestroyModelMixin):
permission_classes = [IsSafeGuard]
def get(self, request):
pay = Peyment.objects.filter(
email=request.user.email,
status=0,
)
serializer = PeymentSerializer(instance=pay, many=True)
return Response(serializer.data)
this is related Serializer class for get request:
class PeymentSerializer(ModelSerializer):
producttitle = serializers.SerializerMethodField()
def get_producttitle(self, obj):
return obj.product.title
productprice = serializers.SerializerMethodField()
def get_productprice(self, obj):
return obj.product.price
def get_discount(self, obj):
return obj.product_discount.discount
#product_discount = ProductDiscountControllSerializer(many=True,read_only=True)
class Meta:
model = Peyment
fields = [
'product',
'id',
'producttitle',
'productprice',
'discount',
'status',
'user',
'email',
'transfer_id',
'created_date',
'updated_date',
]
read_only_fields = ['email', 'user', 'producttitle', 'productprice']
this is Product model:
class Product(models.Model):
product_id = models.AutoField(primary_key=True)
author = models.ForeignKey(User, on_delete=models.CASCADE, db_index=True)
title = models.CharField(max_length=200)
video_length = models.CharField(max_length=20, null=True, blank=True)
mini_description = models.CharField(max_length=1000, null=True, blank=True)
full_description = models.TextField(null=True, blank=True)
you_need = models.CharField(max_length=1000, null=True)
you_learn = models.CharField(max_length=2000, null=True)
price = models.CharField(max_length=50, null=True, blank=True)
video_level = models.CharField(max_length=100, null=True, blank=True)
created_date = models.DateTimeField(auto_now_add=True)
updated_date = models.DateTimeField(auto_now=True)
image = models.FileField(upload_to=upload_to_custom_p,null=True,blank=True)
Peyment model:
class Peyment(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE, to_field='product_id',
related_name='product_peyment')
status = models.CharField(max_length=30, null=True)
user = models.ForeignKey(User, on_delete=models.DO_NOTHING)
transfer_id = models.CharField(max_length=100, null=True, blank=True)
email = models.EmailField()
created_date = models.DateTimeField(auto_now_add=True)
updated_date = models.DateTimeField(auto_now=True)
and discount model:
class ProductDiscountControll(models.Model):
product = models.OneToOneField(Product, on_delete=models.CASCADE, to_field='product_id',
related_name='product_discount')
discount = models.IntegerField(max_length=50, null=True, blank=True)
discount_code = models.CharField(max_length=50, null=True, blank=True)
discount_code_precent = models.CharField(max_length=80, null=True, blank=True)
updated_date = models.DateTimeField(auto_now=True)
updated :
# product peyment
class PeymentSerializer(ModelSerializer):
producttitle = serializers.SerializerMethodField()
def get_producttitle(self, obj):
return obj.product.title
productprice = serializers.SerializerMethodField()
def get_productprice(self, obj):
return obj.product.price
def get_discount(self, obj):
serializer = ProductDiscountControllSerializer(obj.product.product_discount)
return serializer.data
class Meta:
model = Peyment
fields = [
'product',
'id',
'producttitle',
'productprice',
'discount',
'status',
'user',
'email',
'transfer_id',
'created_date',
'updated_date',
]
read_only_fields = ['email', 'user', 'producttitle', 'productprice']
You can just use product.product_discount field name in serializer's method. To return serialized data you should pass this value to ProductDiscountControllSerializer and return serializer.data:
def get_discount(self, obj):
discount = getattr(obj.product, 'product_discount', None)
if discount:
serializer = ProductDiscountControllSerializer(discount)
return serializer.data
return None
UPD
You should explicitly declare discount field in serializer with SerializerMethodField to use it in fileds list:
class PeymentSerializer(ModelSerializer):
discount = serializers.SerializerMethodField()