Serializing ManyToManyField in DjangoRestFramework - django

I have 2 models here Tag and Question. All i want is to serialize the Tag Model without explicitly inside the Question Serializer where Tag model is related by ManyToMany relation with Question model.
class Question(models.Model):
question = models.TextField(blank=False, null=False)
question_image = models.ImageField(blank=True, null=True, upload_to='question')
opt_first = models.CharField(max_length=50, blank=False, null=False)
opt_second = models.CharField(max_length=50, blank=False, null=False)
opt_third = models.CharField(max_length=50, blank=False, null=False)
opt_forth = models.CharField(max_length=50, blank=False, null=False)
answer = models.CharField(max_length=1, choices=(('1','1'),('2','2'),('3','3'),('4','4')))
description = models.TextField(blank=True,null=True )
tag = models.ManyToManyField(Tag)
created_on = models.DateTimeField(default= timezone.now)
class Tag(models.Model):
name = models.CharField(max_length = 50, null=False, unique=True)
And I have serializers classes for these two models
class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tag
fields = ('name',)
class QuestionSerializer(serializers.ModelSerializer):
# tag = TagSerializer(many=True)
def to_representation(self, obj):
rep = super(QuestionSerializer, self).to_representation(obj)
rep['tag'] = []
for i in obj.tag.all():
# rep['tag'].append({'id':i.id,'name':i.name})
# Below doesn't give JSON representation produces an error instead
rep['tag'].append(TagSerializer(i))
return rep
class Meta:
model = Question
fields = ('question', 'question_image', 'opt_first', 'opt_second', 'opt_third', 'opt_forth', 'answer', 'description', 'tag')
read_only_fields = ('created_on',)
Here on using TagSerializer in the to_repesentation method of QuestionSerializer doesn't serialize the tag object. Instead produces error
ExceptionValue : TagSerializer(<Tag: Geography>):
name = CharField(max_length=50, validators=[<UniqueValidator(queryset=Tag.objects.all())>]) is not JSON serializable

You are trying to serialize TagSerializer class. Try to change code to serialize data:
for i in obj.tag.all():
# rep['tag'].append({'id':i.id,'name':i.name})
# Below doesn't give JSON representation produces an error instead
ser = TagSerializer(i)
rep['tag'].append(ser.data)
Also I didn't get why you are override to_representation method.
Try just to define tag field in QuestionSerializer:
tag = TagSerializer(read_only=True, many=True)

Related

How do I pull in data from multiple models into a specific model serializer?

I have this model that represents a bookmark or favorite. It has multiple foreign keys to other models. In the api I would like to pull in the data from each of the models that is referenced in the particular bookmark.
The model:
class Bookmark(models.Model):
marktype = models.CharField(max_length=10)
post = models.OneToOneField(Post, on_delete=models.CASCADE, null=True, blank=True)
question = models.OneToOneField(Question, on_delete=models.CASCADE, null=True, blank=True)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True, verbose_name="created at")
updated_at = models.DateTimeField(auto_now=True, verbose_name="updated at")
class Meta:
verbose_name = "bookmark"
verbose_name_plural = "bookmarks"
ordering = ["created_at"]
db_table = "bookmarks"
def __str__(self):
return "{}'s bookmark".format(self.owner.username)
I tried to use a SerializerMethodField but I get an error: 'NoneType' object has no attribute 'id'
Here is the serializer
class BookmarkSerializer(serializers.ModelSerializer):
post = serializers.SerializerMethodField()
question = serializers.SerializerMethodField()
class Meta:
model = Bookmark
fields = '__all__'
def get_post(self, obj):
obj = Post.objects.get(id=obj.post.id)
post = ShortPostSerializer(obj)
return post.data
def get_question(self, obj):
obj = Question.objects.get(id=obj.question.id)
question = ShortQuestionSerializer(obj)
return question.data
what am I doing wrong please?
You can update your serializer like the following (You can short it as you want or use your ShortQuestionSerializer as well instead of QuestionSerializer),
class QuestionSerializer(serializers.ModelSerializer):
class Meta:
model = Question
fields = '__all__'
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = '__all__'
class BookmarkSerializer(serializers.ModelSerializer):
post = PostSerializer()
question = QuestionSerializer()
class Meta:
model = Bookmark
fields = '__all__'

how to use django Serializer or signal to add object in database?

I create ticket , ticketflow , ticketstate , tickettype models
i need a serializer or signal that when user create ticket programmatically add ticketflow object and set state of ticket to submited or something else
Here is my models
class TicketType(models.Model):
title = models.CharField(max_length=255, blank=False, unique=True, null=False)
def __str__(self):
return self.title
class TicketState(models.Model):
title = models.CharField(max_length=255, blank=False, unique=True, null=False)
def __str__(self):
return self.title
class Ticket(models.Model):
id = models.UUIDField(primary_key=True, default=uuid4 , editable=False)
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete= models.CASCADE)
ticket_type = models.ForeignKey(TicketType,on_delete=models.CASCADE , default=1)
title = models.CharField(max_length=255, blank=False, null=False)
message = models.TextField()
attachment = models.FileField(upload_to='uploads/tickets/', validators=[FileExtensionValidator(allowed_extensions=['pdf','docx','zip','jpg','png'])], blank=True)
created_on = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-created_on']
def __str__(self):
return self.title
class TicketFlow(models.Model):
uuid = models.UUIDField(default=uuid4, editable=False)
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete= models.CASCADE)
ticket = models.ForeignKey(Ticket,on_delete=models.CASCADE , related_name='ticketflow')
ticket_state = models.ForeignKey(TicketState,on_delete=models.CASCADE , default=1 , related_name='ticketstate')
message = models.TextField()
attachment = models.FileField(upload_to='uploads/tickets/', validators=[FileExtensionValidator(allowed_extensions=['pdf','docx','zip','jpg','png'])], blank=True)
created_on = models.DateTimeField(auto_now_add=True)
updated_on = models.DateTimeField(auto_now= True)
class Meta:
ordering = ['-created_on']
here is my serializers
class TicketTypeSerializer(serializers.ModelSerializer):
class Meta:
model = TicketType
fields = ('id','title',)
class TicketStateSerializer(serializers.ModelSerializer):
class Meta:
model = TicketState
fields = ('id','title',)
class TicketSerializer(serializers.ModelSerializer):
class Meta:
model = Ticket
fields = ['id' , 'author', 'ticket_type','title' ,'message' , 'attachment' , 'created_on']
class TicketFlowSerializer(serializers.ModelSerializer):
class Meta:
model = TicketFlow
fields = ['author', 'ticket_state', 'message', 'attachment', 'created_on', 'updated_on']
It'll be great if someone can help me out in this. how can i create signal or override create method in serializers
You probably want your "state" field to be read-only in the serializer, this way it can only be changed programmatically, and in the model set a default value with default='pending'.
Then you can override the update method in a Serializer (see the doc here):
def update(self, instance, validated_data):
validated_data['state'] = 'edited'
return super(MySerializer, self).update(instance, validated_data)

drf create manytomany fields

models
class CreatorRawArtwork(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=500)
descripton = models.TextField()
editions = models.IntegerField(null=True, blank=True)
price = models.CharField(max_length=500)
created_at = models.DateTimeField(auto_now_add=True, null=True, blank=True)
medias = models.FileField(null=True, blank=True, upload_to="raw-medias")
user = models.ForeignKey(to=Login, on_delete=models.CASCADE, related_name="creatorrawartwork", null=True, blank=True
)
collection = models.ForeignKey(
to=DesignerCollection, on_delete=models.CASCADE, related_name="creatorrawartwork", null=True, blank=True)
categories = models.ManyToManyField(DesignerCategories, related_name='creatorrawartwork')
def __str__(self):
return self.title
serializer
class CreatorRawArtworkSerializer(serializers.ModelSerializer):
categories = serializers.PrimaryKeyRelatedField(queryset=DesignerCategories.objects.all(), many=True)
class Meta:
model = CreatorRawArtwork
fields = "__all__"
depth=1
views
class CreatorRawArtworkView(viewsets.ModelViewSet):
queryset = CreatorRawArtwork.objects.all()
serializer_class = CreatorRawArtworkSerializer
Here i am trying to create manytomany fields using drf serialier it is showing some error
plese check the screenshot for parameter and responses
What can be the issue please take a look
class CreatorRawArtworkSerializer(serializers.ModelSerializer):
collection = DesignerCollectionSerializer(read_only=True) #assuming you have already defined serializer for *DesignerCollectionSerializer*
categories = DesignerCategoriesSerializer(many=True)
class Meta:
model = CreatorRawArtwork
fields = "__all__"
depth=1
I tested with your code and your code is working fine
just make sure your request data is json

Django rest framework IntegrityError(1048, "Column 'Board_id' cannot be null")

The error below occurs when attempting to create a comment.
enter image description here
And my code is as follows. I want to know the solution.
Help me. I'm such a beginner.
models.py
class Board(models.Model):
b_no = models.AutoField(primary_key=True)
b_title = models.CharField(max_length=255)
b_note = models.TextField(null=True, help_text="")
b_writer = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
parent_no = models.IntegerField(default=0, null=True)
b_date = models.DateTimeField(auto_now_add = True, blank=True, null=True)
b_count = models.PositiveIntegerField(default=0)
usage_flag = models.CharField(null=True, max_length=10, default='1')
class Comment(models.Model):
Board = models.ForeignKey(Board, on_delete=models.CASCADE)
c_writer = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
c_note = models.TextField(null=True, help_text="")
c_date = models.DateTimeField(auto_now_add = True, blank=True, null=True)
serializers.py
class CommentSerializer(serializers.ModelSerializer):
class Meta:
model = Comment
fields = ['c_writer', 'c_note', 'c_date']
class CommentCreateSerializer(serializers.ModelSerializer):
class Meta:
model = Comment
fields = ['c_writer', 'c_note']
views.py
class CommentCreateView(CreateAPIView):
# lookup_field = 'no'
queryset = Comment.objects.all()
serializer_class = CommentCreateSerializer
# def form_vaild(self, form):
# comment = form.save(commit=False)
# comment.writer = self.request.user
# comment.board = get_object_or_404(Board, pk=self.kwargs['board_pk'])
# return super().form_valid(form)
class CommentDeleteView(DestroyAPIView):
# lookup_field = 'no'
queryset = Comment.objects.all()
serializer_class = CommentSerializer
urls.py
path('boardapi/<int:board_pk>/comment/create/', views.CommentCreateView.as_view(), name='CommentCreateView'),
path('boardapi/<int:board_pk>/comment/<int:pk>/delete/', views.CommentDeleteView.as_view(), name='CommentDeleteView'),
This article is helpful for you please read.
Class Based Views
While functions are easy to work with, it’s often beneficial to use class based views to reuse functionality, especially for large APIs with a number of endpoints.
https://realpython.com/django-rest-framework-class-based-views/

how to use RelatedField in Django rest framework?

I have problem with Django restframe work i have 2 table that one of them is a foreign key to another i have used RelatedField in serializer but i get an error:'Relational field must provide a queryset argument,
can someone help me in this case
my code is as below:
class DocTable(models.Model):
project = models.CharField(max_length=1000, null=True, blank=True)
document_no = models.CharField(max_length=1000, null=True, blank=True)
document_title = models.TextField(null=True, default='', blank=True)
class PlanTable(models.Model):
document = models.ForeignKey(DocTable, on_delete=models.CASCADE, related_name='doctable')
work_type = models.CharField(max_length=1000, null=True, blank=True)
description_work = models.TextField(null=True, default='', blank=True)
serializers.py
class DocTableSerializer(serializers.ModelSerializer):
doctable = serializers.RelatedField(many=True)
class Meta:
model = DocTable
fields = ['pk', 'project', 'document_no', 'doctable']
read_only_fields = ['pk']
class PlanTableSerializer(serializers.ModelSerializer):
class Meta:
model = PlanTable
fields = ['pk', 'document', 'work_type', 'description_work']
read_only_fields = ['pk']
views.py
class DocTableListView(generics.ListAPIView):
lookup_field = 'pk'
serializer_class = DocTableSerializer
def get_queryset(self):
return PlanTable.objects.all()
def get_object(self):
pk = self.kwargs.get('pk')
return PlanTable.objects.get(pk=pk)
You have to provide queryset in RelatedField like this.
class DocTableSerializer(serializers.ModelSerializer):
doctable = serializers.RelatedField(many=True, queryset=DocTable.objects.all())
Or if you only want to use this related field for retrieving data, you can mark it as read only
doctable = serializers.RelatedField(many=True, read_only=True)