Field list_items is not showing in the API request.
I want to create request to get TodoItem with list of ListItem objects related to TodoItem.
I tried to change types of list_items value to another, but it isn't working.
Response right now:
[
{
"id": 1,
"type": "L",
"title": "Some title",
"due_date": null,
"created_at": "2022-08-02T09:26:07.149081Z",
"text_value": "",
"url_value": ""
}
]
Response I need:
[
{
"id": 1,
"type": "L",
"title": "Some title",
"due_date": null,
"created_at": "2022-08-02T09:26:07.149081Z",
"text_value": "",
"url_value": ""
"list_items":[
Item #1,
Item #2,
]
}
]
models.py
class TodoItem(models.Model):
id = models.AutoField(primary_key=True)
type = models.CharField(max_length=1, choices=(
('T', 'String'), ('L', 'List'), ('U', 'URL')))
title = models.CharField(max_length=200, blank=False, null=False)
due_date = models.DateField(null=True)
created_at = models.DateTimeField(auto_now_add=True)
text_value = models.TextField(blank=True, max_length=500)
url_value = models.URLField(blank=True) # TODO: add validator/test it
class ListItem(models.Model):
id = models.AutoField(primary_key=True)
value = models.CharField(max_length=100)
checked = models.BooleanField(default=False)
todo_item = models.ForeignKey(TodoItem, on_delete=models.CASCADE)
position = PositionField(default=0, unique_for_fields=('todo_item',))
serializers.py
class ListItemSerializer(serializers.ModelSerializer):
todo_item = serializers.PrimaryKeyRelatedField(
queryset=TodoItem.objects.all(), required=False, allow_null=True, default=None)
class Meta:
model = ListItem
fields = ['id', 'value', 'position', 'todo_item']
class TodoItemSerializer(serializers.ModelSerializer):
created_at = django_filters.DateFromToRangeFilter()
def get_list_items(self, obj):
return ListItemSerializer(many=True, read_only=True).data
class Meta:
model = TodoItem
fields = '__all__'
I think you need to set the related_name in the ForeignKey field.
class ListItem(models.Model):
...
todo_item = models.ForeignKey(TodoItem, on_delete=models.CASCADE, related_name = "list_items")
position = PositionField(default=0, unique_for_fields=('todo_item',))
Then in the serializer, you can set the list_items field.
class TodoItemSerializer(serializers.ModelSerializer):
created_at = django_filters.DateFromToRangeFilter()
list_items = ListItemSerializer(many= True, read_only = True)
class Meta:
model = TodoItem
fields = ('id', 'type', 'title', 'due_at', 'created_at', 'text_value', 'url_value', 'list_items', )
Related
I have two api's:
Article api:
{
"id": 2,
"title": "123",
"author": 2,
"showing_this": [
{
"id": 1,
"title": "lol",
}
],
"token": [
{
"id": 1,
"token": "123"
},
{
"id": 3,
"token": "qweqer"
}
]
},
User api:
{
"email": "a#a.com",
"token": [
{
"id": 1,
"token": "123",
}
{
"id": 2,
"token": "aaa",
}
]
}
How can I only show "showing_this" in Article api if token in article api matches token in user api?
This is my Article serializer:
class ArticleSerializer(FlexFieldsModelSerializer):
showing_this = ShowingThisSerializer(many=True)
Token = TokenSerializer(many=True, read_only=True)
class Meta:
model = Article
fields = ['id', 'title', 'author', 'showing_this', 'token']
Token serializer:
class TokenSerializer(serializers.ModelSerializer):
class Meta:
model = Token
fields = ['id', 'token',]
Showing this serializer:
class ShowingThisSerializer(serializers.ModelSerializer):
class Meta:
model = ShowingThis
fields = ['id', 'title',]
Models:
class ShowingThis(models.Model):
article = models.ForeignKey(Article, related_name="showings", on_delete=models.CASCADE)
title = models.CharField(max_length=100)
class Token(models.Model):
token = models.CharField(max_length=100)
date_added = models.DateTimeField(default=timezone.now)
Token model from USER API:
class Token(models.Model):
user = models.ForeignKey(NewUser, related_name="tokens", on_delete=models.CASCADE)
article = models.ForeignKey(settings.TOKEN_MODEL, related_name="tokens", on_delete=models.CASCADE)
token = models.CharField(max_length=100)
date_added = models.DateTimeField(default=timezone.now)
Is it possible to create permissions in ArticleSerializer? How can I map through users' tokens and compare to the ones in the article and if there is a match than show content in "showing_this".
Not exactly permissions but you could filter your to_representation in the serializer
New answer based on comments:
based on this Remove null fields from Django Rest Framework response
what you need to do is change the ArticleSerialzier
class ArticleSerializer(FlexFieldsModelSerializer):
showing_this = ShowingThisSerializer(many=True)
Token = TokenSerializer(many=True, read_only=True)
class Meta:
model = Article
fields = ['id', 'title', 'author', 'showing_this', 'token']
def to_representation(self, instance):
result = super(ArticleSerializer, self).to_representation(instance)
response = []
for key in result:
if key == 'showing_this':
user_token_ids = self.content['request'].user.token_set.values_list('id',flat=True)
if any(article_token['id'] in user_token_ids for article_token in result['token']):
response.append((key, result[key]))
response.append((key, result[key]))
return OrderedDict(response)
Old answer: I thought you would want to filter articles
this would filter articles by matching user tokens
class ArticeleViewset(viewsets.ModelViewSet):
...
serializer = ArticleSerializer
def get_queryset(self):
user_match_ids= Token.objects.filter(user=self.request.user).values('article_id')
queryset = Article.objects.filter(id__in=user_match_ids)
return queryset
I am a newbie with django rest framework and python. and it is first time I asking a question here. thanks for helps from now..
--------------my models
class defined_views(models.Model):
name = models.CharField(max_length=150)
class defined_permissions(models.Model):
name = models.CharField(max_length=150)
class menuler(models.Model):
adi= models.CharField(max_length=150, null=True)
sira= models.PositiveIntegerField(null=True, blank=True)
parentId= models.ForeignKey('self', null=True, on_delete=models.CASCADE)
viewId= models.ForeignKey(defined_views, null=True, on_delete=models.CASCADE)
menu_type= models.CharField(max_length=150, null=True)
class user_menu_permission(models.Model):
userId = models.ForeignKey(User, null=False, on_delete=models.CASCADE)
menuID = models.ForeignKey(menuler, null=False, on_delete=models.CASCADE)
permissionID = models.ForeignKey(defined_permissions, null=True, on_delete=models.CASCADE)
-------------------serializer
class menulerSerializer(serializers.ModelSerializer):
class Meta:
model = menuler
fields = ['id', 'adi', 'sira', 'parentId', 'viewId', 'menu_type']
class user_menu_permissionSerializer(serializers.ModelSerializer):
menu = menulerSerializer()
class Meta:
model = user_menu_permission
fields = ['menuID', 'permissionID', 'menu']
class UserSerializer(serializers.ModelSerializer):
menuler = user_menu_permissionSerializer(
source='user_menu_permission_set', many=True)
class Meta:
model = User
fields = ['id', 'username', 'menuler']
------------------and view
class userView(APIView):
def get(self, request):
queryset = User.objects.all()
serializer = UserSerializer(queryset, many=True)
return Response(serializer.data)
I get this errror
"Got AttributeError when attempting to get a value for field menu on serializer user_menu_permissionSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the user_menu_permission instance.
Original exception text was: 'user_menu_permission' object has no attribute 'menu'."
if I change user_menu_permissionSerializer like that
class user_menu_permissionSerializer(serializers.ModelSerializer):
class Meta:
model = user_menu_permission
fields = ['menuID', 'permissionID']
I get result like that bu I want get menu as tree also.. but unfortunetly...
[
{
"id": 1,
"username": "admin",
"menuler": []
},
{
"id": 2,
"username": "taner.kader",
"menuler": [
{
"menuID": 2,
"permissionID": 1
},
{
"menuID": 3,
"permissionID": 1
},
{
"menuID": 5,
"permissionID": 1
}
]
}
]
I have solved like below
models
class defined_views(models.Model):
name = models.CharField(max_length=150)
class defined_permissions(models.Model):
name = models.CharField(max_length=150)
class menuler(models.Model):
adi= models.CharField(max_length=150, null=True)
sira= models.PositiveIntegerField(null=True, blank=True)
parentId= models.ForeignKey('self', null=True, on_delete=models.CASCADE)
viewId= models.ForeignKey(defined_views, null=True, on_delete=models.CASCADE)
menu_type= models.CharField(max_length=150, null=True)
permissionID = models.ManyToManyField(defined_permissions, through='user_menu_permission')
userId = models.ManyToManyField(User, through='user_menu_permission')
class user_menu_permission(models.Model):
# userId = models.ForeignKey(User, related_name='kullanici_menuler', null=False, on_delete=models.CASCADE)
userId = models.ForeignKey(User, null=False, on_delete=models.CASCADE)
menuID = models.ForeignKey(menuler,null=False, on_delete=models.CASCADE)
permissionID = models.ForeignKey(defined_permissions, null=True, on_delete=models.CASCADE)
serializers
class defined_permissionsSerializer(serializers.ModelSerializer):
class Meta:
model = defined_permissions
fields = ['id', 'name']
class defined_viewsSerializer(serializers.ModelSerializer):
class Meta:
model = defined_views
fields = ['id', 'name']
class menulerSerializer(serializers.ModelSerializer):
class Meta:
model = menuler
fields = ['id', 'adi', 'sira', 'parentId', 'viewId', 'menu_type']
# fields = ['adi']
class user_menu_permissionSerializer(serializers.ModelSerializer):
# menu = menulerSerializer(many=True)
class Meta:
model = user_menu_permission
fields = ['menuID', 'permissionID']
class UserSerializer(serializers.ModelSerializer):
# menuler = user_menu_permissionSerializer(
# source='user_menu_permission_set', many=True)
# kullanici_menuler = user_menu_permissionSerializer(many=True)
kullanici_menuler= menulerSerializer(source='menuler_set', many=True)
class Meta:
model = User
fields = ['id', 'username', 'kullanici_menuler']
and result
[
{
"id": 1,
"username": "admin",
"kullanici_menuler": []
},
{
"id": 2,
"username": "tayfun.uzun",
"kullanici_menuler": [
{
"id": 2,
"adi": "Yapılacaklar Listesi",
"sira": 1,
"parentId": 1,
"viewId": 1,
"menu_type": "view"
},
{
"id": 3,
"adi": "Raporlamalar",
"sira": 2,
"parentId": 1,
"viewId": 2,
"menu_type": "view"
},
{
"id": 5,
"adi": "Süreç İşleyişleri",
"sira": 1,
"parentId": 4,
"viewId": 3,
"menu_type": "view"
}
]
}
]
Try below something like this:
serializer.py :
class user_menu_permissionSerializer(serializers.ModelSerializer):
menu = menulerSerializer(many=True)
class Meta:
model = user_menu_permission
fields = ['menuID', 'permissionID', 'menu']
views.py :
class userView(APIView):
def get(self, request):
data = User.objects.all()
serializer = UserSerializer(data, many=True)
return Response(serializer.data)
I am trying to get serialized data for the below model with foreign keys but in the output i am only getting the ids instead of the fields of the model associated with hyperlink.
I have tried getting all the fields of the Skills model using the commented lines in the profile serializer but no luck
models.py
class Profile(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
first_name = models.CharField(max_length=20, null=True)
last_name = models.CharField(max_length=20, null=True)
def __str__(self):
return 'Profile for user {}'.format(self.user.username)
class Skill(models.Model):
skill = models.CharField(max_length=20, null=True)
level = models.CharField(max_length=20, null=True)
user = models.ForeignKey(Profile, null=True,
on_delete=models.PROTECT, related_name='skills')
def __str__(self):
return '%s: %s: %s' % (self.user, self.skill, self.level)
serializer.py
class SkillSerializer(serializers.ModelSerializer):
class Meta:
model = Skill
fields = ('user', 'skill', 'level')
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
# skills = SkillSerializer(many=True, read_only=True) # serializes child model's data inside this model's data
# skills = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='skill-detail')
# skills = serializers.StringRelatedField(many=True)
# skills = serializers.HyperlinkedIdentityField( view_name = "skill-list", lookup_field = "user")
url = HyperlinkedIdentityField( view_name="profile-detail", lookup_field = "id")
# user = serializers.ReadOnlyField(source='user.username')
# pdb.set_trace()
model = Profile
fields = ['id', 'user', 'url', 'skills']
views.py
class ProfileList(generics.ListCreateAPIView):
queryset = Profile.objects.all()
serializer_class = ProfileSerializer
class ProfileDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Profile.objects.all()
serializer_class = ProfileSerializer
class SkillList(generics.ListCreateAPIView):
queryset = Skill.objects.all()
serializer_class = SkillSerializer
class SkillDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Skill.objects.all()
serializer_class = SkillSerializer
urls.py
path('profiles/', views.ProfileList.as_view(), name='profile-list'),
path('profiles/<int:pk>/', views.ProfileDetail.as_view(), name='profile-detail'),
path('skills/', views.SkillList.as_view(), name='profile-list'),
path('skills/<int:pk>/', views.SkillDetail.as_view(), name='skill-list'),
Output: http://127.0.0.1:8000/authenticator/profiles/
[ "id": 6,
"user": 4,
"url": "http://127.0.0.1:8000/authenticator/profiles/6/",
"skills": [
57,
55
],
]
Expected output:
[ "id": 6,
"user": 4,
"url": "http://127.0.0.1:8000/authenticator/profiles/6/",
"skills": [
{
"user": 6,
"skill": "ABC",
"level": "Beginner"
},
{
"user": 6,
"skill": "DEF",
"level": "Intermediate"
},
]
]
This should normally work with the following in serializer.py:
class ProfileSerializer(serializers.ModelSerializer):
skills = SkillSerializer(many=True, read_only=True) # serializes child model's data inside this model's data
url = HyperlinkedIdentityField( view_name="profile-detail", lookup_field = "id")
class Meta:
model = Profile
fields = ['id', 'user', 'url', 'skills']
So basically uncomment the line in which the ProfileSerializer is told to serialize the skills with your SkillsSerializers, such that the entire skill objects are included in the result instead of its IDs.
You can use the concept of nested serializer for the solution.
Create two serializer ProfileReadSerializer and ProfileWriteSerializer
serializers.py
class SkillSerializer(serializers.ModelSerializer):
class Meta:
model = Skill
fields = ('user', 'skill', 'level')
class ProfileReadSerializer(serializers.ModelSerializer):
skills = SkillSerializer(many=True, read_only=True)
url = HyperlinkedIdentityField( view_name="profile-detail", lookup_field = "id")
class Meta:
model = Profile
fields = ('id', 'user', 'url', 'skills')
class ProfileWriteSerializer(serializers.ModelSerializer):
skills = SkillSerializer(many=True)
class Meta:
model = Profile
fields = ('id', 'user', 'url', 'skills')
In views you simply can use ModelViewSet to make things easy and use get_serializer_class
views.py
from rest_framework.viewsets import ModelViewSet
class ProfileVewSet(ModelViewSet):
queryset = Profile.objects.all()
def get_serializer_class(self):
if self.request.method == 'POST' or self.request.method == 'PUT' or self.request.method == 'PATCH':
return ProfileWriteSerializer
else:
return ProfileReadSerializer
And at last if you are using ModelViewSet you need to change the urls.py
urls.py
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register('profile', views.ProfileViewSet, base_name='profile')
urlpatterns = [
path('', include(router.urls))
]
I think this will solve your problem. Please have a look.
Currently I an getting following response, because of nested serializer. I have nested product serializer inside cart serializer. By doing like that, I get following result. But want all attributes of product in main section(outside the product, as shown below)
{
"product": {
"id": 1,
"name": "Ghost Peanut Butter Cereal Milk Whey Protein",
"product_code": "B07FLJYP5M",
"description": "Ghost products feature a 100% transparent label that fully discloses the dose of each active ingredient.",
"price": "5000.00",
"photo": "https://images-na.ssl-images-amazon.com/images/I/61WZazUpWsL._SX522_.jpg",
"link_to_amazon": "https://www.amazon.com/dp/B07FLJYP5M/?tag=1230568-20"
},
"description": null,
"default": "Yes"
}
But I want the response like below:
{
"name": "Ghost Peanut Butter Cereal Milk Whey Protein",
"product_code": "B07FLJYP5M",
"description": "Ghost products feature a 100% transparent label that fully discloses the dose of each active ingredient.",
"price": "5000.00",
"photo": "https://images-na.ssl-images-amazon.com/images/I/61WZazUpWsL._SX522_.jpg",
"link_to_amazon": "https://www.amazon.com/dp/B07FLJYP5M/?tag=1230568-20",
"description": null,
"default": "Yes"
}
models.py
class DefaultCart(models.Model):
# Default Cart in Model class
YES = 'Yes'
NO = 'No'
DEFAULT_CHOICES = (
(YES, 'Yes'),
(NO, 'No'),
)
product = models.ForeignKey(Product, related_name='product', on_delete=models.CASCADE)
description = models.TextField(blank=True, null=True)
default = models.CharField(
max_length=3,
choices=DEFAULT_CHOICES,
default=YES,
)
serializers.py
class ProductSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Product
fields=(
'id','name','product_code','description','price','photo','link_to_amazon'
)
class DefaultCartSerializer(serializers. HyperlinkedModelSerializer):
product = ProductSerializer(read_only=True)
class Meta:
model = DefaultCart
fields = (
'product',
'description',
'default'
)
read_only_fields = ('id',)
views.py
def index(request):
# retrive all default_carts or create new default_cart
if request.method == 'GET':
default_carts = DefaultCart.objects.all()
serializer = DefaultCartSerializer(default_carts, many=True)
return Response(serializer.data)
Here I have solved my problem by doing following in serializers.py
class DefaultCartSerializer(serializers. ModelSerializer):
product_id = serializers.IntegerField(
required=True,
validators=[UniqueValidator(queryset=DefaultCart.objects.all())]
)
name = serializers.SerializerMethodField('get_product_name')
product_code = serializers.SerializerMethodField('get_product_product_code')
price = serializers.SerializerMethodField('get_product_price')
photo = serializers.SerializerMethodField('get_product_photo')
link_to_amazon = serializers.SerializerMethodField('get_product_link_to_amazon')
class Meta:
model = DefaultCart
fields = (
'id',
'product_id',
'description',
'default',
'name',
'product_code',
'price',
'photo',
'link_to_amazon'
)
read_only_fields = ('id',)
def get_product_name(self, obj):
return obj.product.name
def get_product_product_code(self,obj):
return obj.product.product_code
def get_product_price(self, obj):
return obj.product.price
def get_product_photo(self, obj):
return obj.product.photo
def get_product_link_to_amazon(self, obj):
return obj.product.link_to_amazon
One Book can have many BookContent in different languages. In my example, the Book has 2 BookContents, one in english and the other in chinese.
I am getting the Book and its content in a specific language by specifying the language queryset like this : http://localhost/api/books/?language=english. When this is call, it calls BookList get_query in views.py where I filter the content by language. However, the json results still print all the BookContent for that Book.
Below are my codes.
models.py
class Book(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
title = models.CharField(max_length=255)
class BookContent(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
book = models.ForeignKey(Book, releated_name='content' on_delete=models.CASCADE)
content = models.TextField()
language = models.TextField()
serializers.py
class BookContentSerializer(serializers.ModelSerializer):
class Meta:
model = BookContent
fields = ('id', 'content', 'language')
class BookSerializer(serializers.ModelSerializer):
content = BookContentSerializer(many=True, read_only=True)
class Meta:
model = Book
fields = ('id', 'title', 'content')
views.py
class BookList(generics.ListAPIView):
serializer_class = BookSerializer
permission_classes = (permissions.IsAuthenticated,)
def get_queryset(self):
if 'language' in self.request.query_params:
language = self.request.query_params['language']
return Book.objects.filter(content__language=language).distinct().order_by('title')
class BookDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
permission_classes = (permissions.IsAuthenticated,)
Current Json results:
{
"results": [
{
"id": "d3e5185a-1b7b-427c-bbe3-030bfa2e3bce",
"title": "My Book Title",
"book_content": [
{
"id": "0fea8027-3ecf-4571-a95f-5a09a93408ec",
"content": "hello content 1",
"language": "english"
},
{
"id": "0fea8027-3ecf-4571-a95f-5a09a93408ed",
"content": "你好",
"language": "chinese"
}
]
}
]
}
How do I get a list of Books and the BookContent language for the specific language only?
Expected Json results:
{
"results": [
{
"id": "d3e5185a-1b7b-427c-bbe3-030bfa2e3bce",
"title": "My Book Title",
"book_content":
{
"id": "0fea8027-3ecf-4571-a95f-5a09a93408ec",
"content": "hello content 1",
"language": "english"
}
}
]
}