I leave a question regarding DRF multi-image processing - django

class PostImageSerializer(serializers.ModelSerializer):
class Meta:
model = PostImage
fields = "image"
class PostSerializer(serializers.ModelSerializer):
images = PostImageSerializer(many=True, read_only=True)
class Meta:
model = Post
fields = (
"id",
"author",
"content",
"images",
)
I'd like to get the results the following response from the above communication codes.
(위 코드로 GET 통신에서 아래와 같은 응답 결과를 얻고 싶은데요.)
{
"id": 53,
"author": 1,
"post": "awesome",
"images": {
"image": "abc.png",
"image": "def.jpg",
}
}
The images field does not apply and appears like below.
(images 필드가 적용되지 않고 아래와 같이 나오는 상황입니다.)
{
"id": 53,
"author": 1,
"post": "awesome",
}
Which part should I fix? I also attach the code for the model.
(어떤 부분을 고쳐야할까요? 모델 단 코드도 같이 첨부합니다.)
class Post(models.Model):
author = models.ForeignKey("User", on_delete=models.CASCADE)
post = models.CharField(max_length=100)
class PostImage(models.Model):
post = ForeignKey("Post", on_delete=models.CASCADE)
image = models.ImageField(upload_to="image", blank=True)

Edit models.py
(models.py를 수정하시면 됩니다.)
class Post(models.Model):
author = models.ForeignKey("User", on_delete=models.CASCADE)
post = models.CharField(max_length=100)
class PostImage(models.Model):
post = ForeignKey("Post", on_delete=models.CASCADE, related_name="images")
image = models.ImageField(upload_to="image", blank=True)

Related

How to POST and GET a model with Foreign Key

I am working on a NextJS + Django REST Framework project where I have three models; Document, MySource, and QuestionBlock.
Document is created along with several “question_blocks” linked to the created document. They are created together, and I have already implemented this with nested serializers.
After the Document is created, I want to be able to POST a MySource model linked to the document. Then, when I make a GET request of a document, all mysource objects should be displayed as well.
POST request: notice how I just put the document’s id that I want to link with.
{
"url": "urlasdf",
"title": "tuitle",
"publisher": "afdfas ",
"desc": "qwefqwef",
"summary": "asdfasdf",
"document": "J9DY2pE"
}
GET request: I want the document GET request to show something like below.
"id": "LwpQr6Y",
"question_blocks": [
{
"id": 16,
"document": "LwpQr6Y",
"title": "question 4",
"content": "qweqgadssdffasdf asdf"
},
]
"mysource": [
{
"id": 16,
"url": "google.com",
etc. . .
},
],
"title": "renamed title",
"template": "commonapp",
"updated": "2022-05-19T02:16:00+0000",
"created": "2022-04-21T06:59:05+0000"
The weird part is that I do not see any errors with the code below, and the functionality itself is working properly. But when I attempt to GET the document which has at least one mysource object, it takes at a couple minutes to load, which is making me think there’s something wrong with my code that is perhaps making DRF repeat itself.
models.py
class Document(models.Model):
id = HashidAutoField(primary_key=True)
title = models.CharField(max_length=100, default="Untitled")
template = models.CharField(max_length=100, default="")
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
class QuestionBlock(models.Model):
id = models.AutoField(primary_key=True)
document = models.ForeignKey(
Document,
related_name="question_blocks",
on_delete=models.CASCADE,
null=True,
blank=True,
)
title = models.CharField(max_length=500, default="")
content = models.CharField(max_length=100000, default="", blank=True)
class MySource(models.Model):
id = models.AutoField(primary_key=True)
document = models.ForeignKey(
Document,
related_name="mysource",
on_delete=models.CASCADE,
null=True,
blank=True,
)
url = models.CharField(max_length=500, default="")
title = models.CharField(max_length=500, default="", blank=True)
publisher = models.CharField(max_length=500, default="", blank=True)
desc = models.CharField(max_length=500, default="", blank=True)
summary = models.CharField(max_length=500, default="", blank=True)
serializers.py
class MySourceSerializer(serializers.ModelSerializer):
class Meta:
model = MySource
fields = ("id", "url", "title", "publisher", "desc", "summary")
def to_representation(self, instance):
self.fields["document"] = DocumentSerializer(read_only=True)
return super(MySourceSerializer, self).to_representation(instance)
class DocumentSerializer(serializers.ModelSerializer):
id = HashidSerializerCharField(source_field="documents.Document.id", read_only=True)
question_blocks = QuestionBlockSerializer(many=True)
mysource = MySourceSerializer(many=True)
class Meta:
model = Document
fields = "__all__"
def create(self, validated_data):
question_blocks = validated_data.pop("question_blocks")
document = Document.objects.create(**validated_data)
for qBlock in question_blocks:
QuestionBlock.objects.create(document=document, **qBlock)
document.save()
return document
EDIT: adding the QuestionBlockSerializer for more context
class QuestionBlockSerializer(serializers.ModelSerializer):
document = serializers.PrimaryKeyRelatedField(
pk_field=HashidSerializerCharField(source_field="documents.Document.id"),
read_only=True,
)
class Meta:
model = QuestionBlock
fields = "__all__"
optional_fields = ["content"]
I think that an appropriate way to do this maybe be this one:
###imports
from django.forms.models import model_to_dict
class DocumentListingField(serializers.RelatedField):
def to_representation(self, instance):
return model_to_dict(instance.document)
and then in MySourceSerializer remove the to_representation function and update to something like this:
class MySourceSerializer(serializers.ModelSerializer):
document = DocumentListingField(many=False, read_only=True)
class Meta:
model = MySource
fields = (
"id", "url", "title", "publisher", "desc", "summary", "document")
*Edit: I added the read_only set to True, 'caus the those models are using Hashfields thar are not easily selializable.
**edit:The reason that cause the slow response it's becaus you have a circle call of serializators so the system never know when to stop.
right here:
class MySourceSerializer(serializers.ModelSerializer):
def to_representation(self, instance):
...
self.fields["document"] = DocumentSerializer(read_only=True)
#Mysource its calling Documentserializer
...
#And here:
class DocumentSerializer(serializers.ModelSerializer):
...
mysource = MySourceSerializer(many=True) #this one its calling the MysorceSerialize, so there are a endless loop recursion
source : Django Rest Framework-Custom relational fields

How do I merge data of two objects in Django REST Framework

So let's say I have this 2 models
Poll:
class Poll(models.Model):
title = models.CharField(max_length=255)
is_active = models.BooleanField(default=True)
is_available = models.BooleanField(default=True)
date_created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
Options:
class Option(models.Model):
title = models.CharField(max_length=255)
poll = models.ForeignKey(Poll, on_delete=models.CASCADE)
def __str__(self):
return f'{self.poll.title} - {self.title}'
These two objects are connected with ForeignKey. Now let's say I have a frontend that renders both options and the question (title of the poll) but I only want make a single API call to the backend. Basically I need the API to looked like this:
{
"title": "Which is the best frontend framework?",
"options":[
{
"id": 1,
"title": "React"
},
{
"id": 2,
"title": "Vue"
},
{
"id": 3,
"title": "Angular"
}
]
}
How what method/technique should I use to merge two objects like this?
Based on DRF docs
class OptionSerializer(serializers.ModelSerializer):
class Meta:
model = Option
fields = ['id', 'title']
class PollSerializer(serializers.ModelSerializer):
options = OptionSerializer(source='option_set', many=True)
class Meta:
model = Poll
fields = ['title', 'options']

How to add data from one model to other django?

I am using generics to represent views
class PersonRetrieveView(generics.ListAPIView):
queryset = Person.objects.all()
serializer_class = PersonSerializer
and
class CommentRetrieveView(generics.RetrieveAPIView):
queryset = Comment.objects.all()
serializer_class = CommentSerializer
Person data looks like
{
"id": 2,
"user": {
"first_name": "Testuser",
"last_name": "TestUser1",
"id": 2
},
"name": "Test 2",
"city": "California",
"status": "NotActive",
"phone_number": "9876543222",
"age": 22,
"height": 180
}
and Comment
{
"id": 1,
"comment": "test",
"person": 2
}
Comment linked to Person by id. How can i add data from comment to PersonRetrieveView ?
Serializers looks like this
class PersonSerializer(serializers.ModelSerializer):
user = UserSerializer()
# comment = CommentSerializer()
class Meta:
model = Person
fields = '__all__'
class CommentSerializer(serializers.ModelSerializer):
class Meta:
model = Comment
fields = '__all__'
Model looks like
class Person(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=20)
city = models.CharField(max_length=20)
status = models.CharField(max_length=9, default='NotActive')
phone_number = models.CharField(max_length=10)
class Comment(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
comment = models.CharField(max_length=255)
You have Many-to-one relationship and you did not set related_name on Foreign key so your comments are accessible through comment_set which can be used to nest serializer
class PersonSerializer(serializers.ModelSerializer):
user = UserSerializer()
comments = CommentSerializer(source='comment_set', many=True)
class Meta:
model = Person
fields = [ 'user', 'city', 'comments', ...]
Provided that your Person model has a relation to Comment models, simply add depth = 1 in your Person serializer as follows:
class PersonSerializer(serializers.ModelSerializer):
user = UserSerializer()
class Meta:
model = Person
fields = '__all__'
depth = 1

Django Serlizing multiple foreginkey related models

I am having trouble in showing cross relation data in my api end-point
this is my serlization class:
class ArticleSerializer(serializers.ModelSerializer):
# these two variables are assigned coz, author and category are foregin key
author = serializers.StringRelatedField()
category = serializers.StringRelatedField()
class Meta:
model = Article
fields = '__all__'
Above serialization working fine but not satisfy needs.
And this is my models
from django.db import models
import uuid
class Organization(models.Model):
organization_name = models.CharField(max_length=50)
contact = models.CharField(max_length=12, unique=True)
def __str__(self):
return self.organization_name
class Author(models.Model):
name = models.CharField(max_length=40)
detail = models.TextField()
organization = models.ForeignKey(Organization, on_delete=models.DO_NOTHING)
def __str__(self):
return self.name
class Category(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Article(models.Model):
alias = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='author')
title = models.CharField(max_length=200)
body = models.TextField()
category = models.ForeignKey(Category, on_delete=models.CASCADE)
this is my views:
class ArticleSingle(RetrieveAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
lookup_field = 'alias'
and currently my end-point showing like these but i dont like it:
HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
{
"alias": "029a4b50-2e9a-4d35-afc6-f354d2169c05",
"author": "jhon doe",
"category": "sic-fi",
"title": "title goes here",
"body": "this is body"
}
I want the end-point should show the data with author details like, author, organization_name, contact, etc if you dont understand it, please see my models how i designe it.
The end-point should show each and every related data that with foreign key, i hope you got my issue, thanks for your time
What you are looking for is nested serialization.
Rather than specifying author and category as StringRelatedFields, you should assign them as serializer classes (the same applies to the Organization model):
class OrganizationSerializer(serializers.ModelSerializer):
...
class Meta:
model = Organization
fields = '__all__'
class AuthorSerializer(serializers.ModelSerializer):
organization = OrganizationSerializer()
...
class Meta:
model = Author
fields = '__all__'
class CategorySerializer(serializers.ModelSerializer):
...
class Meta:
model = Category
fields = '__all__'
class ArticleSerializer(serializers.ModelSerializer):
author = AuthorSerializer()
category = CategorySerializer()
class Meta:
model = Article
fields = '__all__'
This mechanism will serialize your data as you desire:
HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
{
"alias": "029a4b50-2e9a-4d35-afc6-f354d2169c05",
"author": {
"name": "jhon doe",
"organization": {
"organization_name": "..."
}
...
}
"category": {
"name": "sic-fi"
}
"title": "title goes here",
"body": "this is body"
}
Note: If you want to perform POST requests for creation of those resources, you can find some useful information here.

How to perform nested serialization in Django?

I am new to Django.I am using Django REST Framework and I need to get json from serializers in the following format:
{
"result" : 200,
"categories" : [{
"id" : "V001",
"name": "Vehicles",
"description": "All types of motor and non-motor vehicles",
"icon": "http://images.maa.ae/static/icons/vehicles.png",
"subcategories": [{
"id" : "V00101",
"name": "Cars",
"description": "Motor Cars",
"subcategories": [{
"id" : "V0010101",
"name": "Passenger Cars",
"description": "All types of passenger cars"
}]
},
{
"id" : "V00102",
"name": "Bikes",
"description": "Bikes",
"subcategories": [{
"id" : "V0010201",
"name": "Motor Bikes",
"description": "All kinds of motor bikes"
},
{
"id" : "V0010202",
"name": "Sports Bikes",
"description": "All kinds of sports bikes"
}]
}]
}]
}
My Model class is:
class Category(models.Model):
_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=128)
description = models.CharField(max_length=150,null=True, blank=True)
icon = models.ImageField(upload_to='icons',null=True, blank=True)
parent_id = models.ForeignKey('self', null=True, blank=True)
and my serializers class is:
class CategorySerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Category
fields = ('_id', 'name', 'description', 'icon')
From above implementation I can get Array of Category objects in JSON format.
But I don't know how can I include 'subcategories' in my serializer class.Please help me to get an output similar to json shown in above format.
Use Django Rest Framework.
http://www.django-rest-framework.org/
Keep your code DRY
from rest_framework import serializers
class CategoriesSerializer(serializers.ModelSerializer):
class Meta:
model = Categories
Views
from rest_framework import viewsets
from .serializers import CategoriesSerializer
class CategoryViewSet(viewsets.ModelViewSet):
queryset = Categories.objects.all()
serializer_class = CategoriesSerializer
Example
models.py:
class Sprints(models.Model):
name = models.CharField(default='', blank=True, max_length=90)
description = models.TextField(default='')
class Tasks(models.Model):
date_posted = models.DateTimeField(auto_now_add=True)
name = models.CharField(default='', blank=True, max_length=90)
end = models.DateTimeField(null=True, blank=True)
sprint = models.ForeignKey(Sprints, related_name='tasks')
class Meta:
ordering = ['-date_posted']
unique_together = ['name', 'sprint']
serializers.py:
class TaskSerializer(serializers.ModelSerializer):
class Meta:
model = Tasks
fields = ('id', 'name', 'date_posted', 'end')
class SprintSerializer(serializers.ModelSerializer):
tasks = TaskSerializer(many=True, read_only=True)
class Meta:
model = Sprints
fields = ('id', 'name', 'description', 'tasks')
views.py
class SprintsViews(viewset.ModelViewSet):
queryset = Sprints.objects.all()
serializer_class = SprintSerializer
You can also add a slug field to the models to make them easier to deal with, but this is how for now :)
You should consider having a look at THIS. The usage of depth meta attribute enables you to retrieve related objects to the depth you set.
By doing so, it automatically retrieves nested data.
It is very convenient to avoid using serializers in both sides and thus having ImportError caused by cycles too.
Use related_name and on_delete on your parent_id field in models.py file
class Category(models.Model):
_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=128)
description = models.CharField(max_length=150,null=True, blank=True)
icon = models.ImageField(upload_to='icons',null=True, blank=True)
parent_id = models.ForeignKey('self', null=True, blank=True, related_name='children', on_delete=models.CASCADE)
Now add the packege pip install djangorestframework-recursive on your project
serializers.py:
##################################
from rest_framework_recursive.fields import RecursiveField
##################################
class CategorySerializer(serializers.ModelSerializer):
children = RecursiveField(many=True)
class Meta:
model = Category
fields = ('_id', 'name', 'description', 'icon', 'parent_id', 'children')
views.py (Serializers view file):
class CategoryListAPIView(generics.ListAPIView):
serializer_class = CategorySerializer
queryset = Category.objects.filter(parent_id__isnull=True)
urls.py:
############################
############################
urlpatterns = [
path('category/', views.CategoryListAPIView.as_view(), name="categoryAPI"),
######################################
]