How to serialize two nested django tables? - python

iI've updated the post and pasted the complete code. can any fix the code for me. actually i want to POST data with album name and multiple images adn serialize the both and at POST request I want the whole submitted data. means.
{
name : My favourite songs list
media: [
{
media : filename1,
media : filename2
}
]
}
#views.py
#api_view(['POST'])
def addAlbum(request):
if request.method == 'POST':
serializer = AlbumSerializer(data=request.data)
albums = request.data.pop('media')
if albums:
name = Album.objects.create(name=request.data['name'])
if serializer.is_valid():
for file in albums:
AlbumImages.objects.create(media = file, album = name)
serializer.save()
return Response(serializer.data, status.HTTP_201_CREATED)
return Response(serializer.errors, status.HTTP_400_BAD_REQUEST)
return Response("Please upload the files", status.HTTP_400_BAD_REQUEST)
return Response("Not found", status.HTTP_400_BAD_REQUEST)
#serializers.py
class AlbumImagesSerializer(serializers.ModelSerializer):
class Meta:
model = AlbumImages
fields = "__all__"
class AlbumSerializer(serializers.ModelSerializer):
albumimages = AlbumImagesSerializer(many=True, read_only=True)
class Meta:
model = Album
fields = "__all__"
#models.py
class Album(models.Model):
name = models.CharField(max_length=30, null=False, blank=False)
def __str__(self):
return self.name
class AlbumImages(models.Model):
album = models.ForeignKey(Album, related_name='albumimages', on_delete=models.CASCADE)
media = models.ImageField(upload_to='album/images')
def __str__(self) -> str:
return f'Files of ' + self.album.name
Album is being generated, files are being associated with album table, but the question is how i'll serialize both tables to show response on post request. waiting for help.

I adjusted your code a little bit but it wasn´t tested.
If you don´t want to adjusted the album-ForeignKey field you must change the behavoiur of saving instead of using .objects.create(). It should work.
You wrote a lot of validations. Your serializer can do that. You can use extra_kwargs = {'media': {'required': True} at your AlbumImage-serialzer for example. If you need more explenation don´t hasitate to ask.
album = Album(**validated_data)`
album.albumimages = albumimages_set
album.save()
#views.py
class AlbumView(APIView):
def post(self, request, *args, **kwargs):
resp = Response()
serializer = AlbumSerializer(data=request.data)
if serializer.is_valid():
resp.data = serializer.save()
else:
resp.status_code = HTTP_400_BAD_REQUEST
resp.data = serializer.errors
return resp
#serializers.py
class AlbumImagesSerializer(serializers.ModelSerializer):
class Meta:
model = AlbumImages
fields = "__all__"
class AlbumSerializer(serializers.ModelSerializer):
albumimages = AlbumImagesSerializer(many=True, read_only=True)
class Meta:
model = Album
fields = "__all__"
def create(self, validated_data):
albumimages = validated_data.pop('albumimages')
albumimages_set = [AlbumImages.objects.create(**element) for element in albumimages ]
album = Album.objects.create(**validated_data)
album.albumimages.set(albumimages_set)
album.save()
return album
#models.py
class Album(models.Model):
name = models.CharField(max_length=30, null=False, blank=False)
def __str__(self):
return self.name
class AlbumImages(models.Model):
album = models.ForeignKey(Album, related_name='albumimages', blank=True, null=True, on_delete=models.CASCADE)
media = models.ImageField(upload_to='album/images')
def __str__(self) -> str:
return f'Files of ' + self.album.name

Related

How to send several fields in the response with a PUT request?

I would like when my PUT request is successful it returns me a response with all the fields in my PlantSerializer because currently the response returns me this:
{
"id":48,
"name":"Jar",
"width":"50",
"height":"50",
"exposure":"None",
"qr_code":"",
"garden":65,
"plant":[
7
]
}
But, I would like the response to return this instead:
{
"id":48,
"name":"Jar",
"width":"50",
"height":"50",
"exposure":"None",
"qr_code":"",
"garden":65,
"plant":[
"id":7,
"name":"Artichoke",
"image":null
]
}
How can I achieve this result?
Here is my serializers and my model class :
class Plot(models.Model):
name = models.CharField(max_length=50)
garden = models.ForeignKey('perma_gardens.Garden', on_delete=models.CASCADE)
width = models.CharField(max_length=50, blank=True, null=True)
height = models.CharField(max_length=50, blank=True, null=True)
plant = models.ManyToManyField('perma_plants.Plant', related_name='%(class)s_plant', blank=True)
# Here is my serializers :
class GardenSerializer(serializers.ModelSerializer):
class Meta:
model = Garden
fields = ('id', 'name',)
class PlantSerializer(serializers.ModelSerializer):
class Meta:
model = Plant
fields = ('id', 'name', 'image')
class ReadPlotSerializer(serializers.ModelSerializer):
garden = GardenSerializer(required=True)
plant = PlantSerializer(many=True)
id = serializers.IntegerField(read_only=True)
class Meta:
model = Plot
fields = '__all__'
read_only_fields = [fields]
class WritePlotSerializer(serializers.ModelSerializer):
class Meta:
model = Plot
fields = '__all__'
And here is my views :
class PlotViewSet(viewsets.ModelViewSet):
queryset = Plot.objects.all()
def create(self, request, *args, **kwargs):
serializer = WritePlotSerializer(data=request.data, many=isinstance(request.data, list))
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, pk):
snippet = self.get_object(pk)
snippet.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
def partial_update(self, request, *args, **kwargs):
instance = self.queryset.get(pk=kwargs.get('pk'))
serializer = WritePlotSerializer(instance, data=request.data, partial=True)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)
def get_serializer_class(self):
if self.action in ("list", "retrieve"):
return ReadPlotSerializer
return WritePlotSerializer
In the fuction partial_update you are utilizing the WritePlotSerializer, which only has the plant field implicitly through the fields=__all__ value. This is probably causing drf to use a PrimaryKeyRelatedField, and as such you don't get all the extra fields you defined in your PlantSerializer.
If I understand correctyl you want to use the WritePlotSerializer in the update but use the ReadPlotSerializer when returning the object. You probably should combine both of them in a single serializer by overriding the update method in order to support updating the nested Plant objects. Here is the related documentation.
Alternatively, if you don't want to update the Plants values you can use a slightly modified version of the ReadPlotSerializer in all calls:
class PlotSerializer(serializers.ModelSerializer):
garden = GardenSerializer(required=True, read_only=True)
plant = PlantSerializer(many=True, read_only=True)
id = serializers.IntegerField(read_only=True)
class Meta:
model = Plot
fields = '__all__'

Django writable nested serializers, create method not working

I have a nested serializer, the create method does not work. I have searched over the internet and no method worked for me. The most popular one is the one listed below.
models.py
class Displays(models.Model):
id = models.CharField(primary_key=True, max_length=32,
default=generate_uuid)
name = models.CharField(max_length=45, blank=True, null=True)
class OrdersDj(models.Model):
id = models.CharField(primary_key=True, max_length=32,
default=generate_uuid)
class AdsDj(models.Model):
id = models.CharField(primary_key=True, max_length=32,
default=generate_uuid)
order = models.ForeignKey(
OrdersDj, on_delete=models.CASCADE, blank=False, null=True)
display = models.ForeignKey(
Displays, on_delete=models.CASCADE, blank=True, null=True)
serializers.py
class DisplaySerializer(serializers.ModelSerializer):
class Meta:
model = Displays
fields = "__all__"
class AdsSerializer(serializers.ModelSerializer):
display = DisplaySerializer()
def create(self, validated_data):
print("validated_data", validated_data)
display_id = validated_data.pop('display')
display = Displays.objects.get(id=display_id)
ad = Displays.objects.create(display=display, **validated_data)
return ad
class Meta:
model = Ads
fields = "__all__"
class OrderSerializer(serializers.ModelSerializer):
ads = AdsSerializer(source="adsdj_set", many=True)
def create(self, validated_data):
validated_data.pop('adsdj_set')
order = Orders.objects.create(**validated_data)
return order
class Meta:
model = Orders
fields = "__all__"
views.py
class AdsCreate(APIView):
def put(self, request):
print('request.data', request.data)
serializer = serializers.AdsSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
print('serializer.data > serializer.valid', serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED)
print('serializer.errors > serializer.invalid', serializer.errors)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
print outs
request.data <QueryDict: {'order': ['18bb2225cf6e407a943f2941072d06de'], 'display': ['91'], 'firstday': ['2021-12-4'], 'lastday': ['2021-12-21'], 'duration': ['17'], 'filetype': ['image/png'], 'originalname': ['Picture1.png'], 'price': ['2550'], 'status': ['0'], 'filehash': ['not available yet'], 'orderByNum': ['-1'], 'imgWidth': ['1061'], 'imgHeight': ['708'], 'image': [<InMemoryUploadedFile: Picture1.png (image/png)>]}>
serializer.errors > serializer.invalid {'display': [ErrorDetail(string='This field is required.', code='required')]}
I am giving the display field to the serializer that is the id of the display. In the create method I find that display and reference it in the new ad object. The display field is present in the request.data and passed to the serializer, the serializer complains that the display field is not present.
One version of sending json data
{"order":"18bb2225cf6e407a943f2941072d06de","display":{"id":91},"firstday":"2021-12-5","lastday":"2021-12-15","duration":11,"image":{},"filetype":"image/png","originalname":"Picture1.png","price":1650,"status":0,"filehash":"not available yet","orderByNum":-1,"imgWidth":1061,"imgHeight":708}
Try using different serializers for creation and representation.
class AdsCreateSerializer(serializers.ModelSerializer):
class Meta:
model = Ads
fields = "__all__"
class AdsSerializer(serializers.ModelSerializer):
display = DisplaySerializer()
class Meta:
model = Ads
fields = "__all__"
For display field, AdsSerializer expects the following structure;
"display": {"id": 91}
whereas you send this;
"display": 91

Rest Framework cant save serializer with foreign key

I have next serializers:
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = '__all__'
class PostSerializer(serializers.ModelSerializer):
category = CategorySerializer()
class Meta:
model = Post
fields = ['id', 'title', 'text', 'date', 'category']
And here is my view:
#api_view(['POST'])
def create_post(request):
serializer = PostSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
else:
return Response(serializer.errors)
return Response(serializer.data)
I want to create new Post object, but when I pass an category id at form it does not work, it is not saving my object. I tried to replace create method at my PostSerializer, to this:
def create(self, validated_data):
category_id = validated_data.pop('category')
post = Post.objects.create(**validated_data, category=category_id)
return post
but this dont work. Using postman formdata it is saying, that category field is required despite I filled it.
Here is my models:
class Category(models.Model):
name = models.CharField(max_length=512)
def __str__(self):
return self.name
class Post(models.Model):
title = models.CharField(max_length=512)
text = models.TextField()
date = models.DateTimeField(auto_now_add=True)
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='category')
You need a category object not just an id, so try this
#api_view(['POST'])
def create_post(request):
category_id = request.data['category'] # or however you are sending the id
serializer = PostSerializer(data=request.data)
if serializer.is_valid():
category = Category.objects.get(id=category_id)
serializer.save(category=category)
else:
return Response(serializer.errors)
return Response(serializer.data)
or you can do something similar in the create method of the serializer

how can i add a new key value to my request.data in django

I would like to know how can I add a new value to my request.data
this is my request.data, structure:
[{'fname': 'john', 'lname': 'Doe'}]
how can I add the age key for example
This is my whole code :
def create(self, request):
formSerializer = self.serializer_class(data = request.data)
#### look Down
request.data['master'] = self.request.user.id
#######
if formSerializer.is_valid():
formSerializer.save()
objectSerializer = TeamSerializer(Team.objects.all(), many=True)
return Response(objectSerializer.data, status =
status.HTTP_201_CREATED)
return Response(formSerializer.errors, status.HTTP_400_BAD_REQUEST)
this is my model
from django.db import models
from users.models import CustomUser
# Create your models here.
class Team(models.Model):
master = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
name = models.CharField(null=False, blank=False, max_length=255)
comment = models.CharField(null=True, blank=True, max_length=255)
i have two input fields ( name + comment ) so i need master field that's why
Here you have to not need to add mater in request.data.
Try this:
def create(self, request):
formSerializer = self.serializer_class(data = request.data)
# request.data['master'] = self.request.user.id
if formSerializer.is_valid():
formSerializer.save(master = self.request.user)
objectSerializer = TeamSerializer(Team.objects.all(), many=True)
return Response(objectSerializer.data, status =
status.HTTP_201_CREATED)
return Response(formSerializer.errors, status.HTTP_400_BAD_REQUEST)
Remove master from serializer's fields
and add this in serializer:
class MYSerializer(serializers.ModelSerializer):
username = serializers.CharField(source='master.username',read_only=True)
class Meta:
model = MY_MODEL
fields = (OTHER_FIELDs,'username')
Source Mean??

NOT NULL constraint failed: device_api_devicegroup.owner_id

I am getting not null contraint failed error while posting a group. How should i fix it? I don't want to show the user in the api so i have not used it in the serializer fields. Do i have to compulsorily add it there?
Here is my model, serializer and APIView
class DeviceGroup(models.Model):
token = models.UUIDField(default=uuid.uuid4, unique=True, editable=False)
name = models.CharField(max_length=250, blank=False, null=False)
owner = models.ForeignKey(User, blank=False, null=False)
class DeviceGroupSerializer(serializers.ModelSerializer):
id = serializers.UUIDField(source='token', format='hex', read_only=True)
class Meta:
model = DeviceGroup
fields = ['id','name']
class DevicesGroupsAPIView(APIView):
permission_classes = (permissions.IsAuthenticated,)
serializer_class = DeviceGroupSerializer
def get_object(self, user, token):
try:
return BaseDevice.objects.filter(owner=user).get(token=token)
except ObjectDoesNotExist:
return error.RequestedResourceNotFound().as_response()
def get(self, request, format=None):
"""
Returns a list of groups
"""
reply = {}
try:
groups = DeviceGroup.objects.filter(owner=request.user)
reply['data'] = DeviceGroupSerializer(groups, many=True).data
except:
reply['data'] = []
return Response(reply, status.HTTP_200_OK)
def post(self, request, format=None):
"""
create a new group
"""
print('request.data', request.data)
print('user', request.user)
serializer = DeviceGroupSerializer(data=request.data)
print('serializer', serializer)
if serializer.is_valid():
serializer.save()
return Response(serializers.data, status.HTTP_200_OK)
return Response(serializer.errors, status.HTTP_204_NO_CONTENT)
see this carefully, user is not in request.data:
serializer = DeviceGroupSerializer(data={
'name':request.data['name'],
'owner':request.user.id,
})
also check that the serializer allows the owner to be used
from django.contrib.auth.models import User
class DeviceGroupSerializer(serializers.ModelSerializer):
id = serializers.UUIDField(source='token', format='hex', read_only=True)
owner = serializers.PrimaryKeyRelatedField(queryset=User.objects.all())
class Meta:
model = DeviceGroup
fields = ['id','name', 'owner']

Categories

Resources