Insert count objects fields in Array Django Rest Framework - python

I get a problem in Django Rest Framework.
class FeedDetailSerializer(ModelSerializer):
user = UserFeedSerializer(read_only=True)
comment_count = SerializerMethodField(default=0)
comment_list = CommentFeedSerializer(many=True, read_only=True)
class Meta:
model = Feed
fields = [
'id',
'comment_count',
'comment_list',
]
def get_comment_count(self, obj):
comment_count = Comment.objects.filter(feed=obj.id, parent__isnull=True).count()
return comment_count
This is the CommentFeedSerializer I've created:
class CommentFeedSerializer(ModelSerializer):
url = comment_detail_url
class Meta:
model = Comment
fields = [
'url',
'id',
'comment',
'posted_on',
]
With this Serializer I've done, API will render like this:
"comment_count": 2,
"comment_list": [
{
"url": "http://localhost:8000/api/v1/comments/2/",
"id": 2,
"comment": "haha",
"reply_count": 0,
"posted_on": "2017-11-24T10:23:28.353000Z"
},
{
"url": "http://localhost:8000/api/v1/comments/1/",
"id": 1,
"comment": "Good",
"reply_count": 1,
"posted_on": "2017-11-24T09:54:48.680000Z"
}
]
But this is very hard to manage. So I want to put comment_count into comment_list: commentlist like below How can I do that?
"comment_list": [
"comment_count": 2,
{
"url": "http://localhost:8000/api/v1/comments/2/",
"id": 2,
"comment": "haha",
"reply_count": 0,
"posted_on": "2017-11-24T10:23:28.353000Z"
},
{
"url": "http://localhost:8000/api/v1/comments/1/",
"id": 1,
"comment": "Good",
"reply_count": 1,
"posted_on": "2017-11-24T09:54:48.680000Z"
}
]

Related

django Many to Many with three table relationships together

I want to create a seralizer with 3 models and many to many relationship:
# models.py
class Permission(models.Model):
permission_name = models.CharField(max_length=20)
class Feature(models.Model):
feature_name = models.CharField(max_length=40)
class Role(models.Model):
name = models.CharField(max_length=40)
permissions = models.ManyToManyField(Permission, through='RolePermission')
features = models.ManyToManyField(Feature, through='RolePermission')
class RolePermission(models.Model):
role = models.ForeignKey(Role, on_delete=models.CASCADE)
permission = models.ForeignKey(Permission, on_delete=models.CASCADE)
feature = models.ForeignKey(Feature, on_delete=models.CASCADE)
Sample data:
PERMISSION:
1 - add
2 - edit
3 - remove
4 - view
FEATURE:
1 - user
2 - device
ROLE:
1 - ROLE1
2 - ROLE2
data i want to response from view:
[
{
"id": 1,
"name": "ROLE1",
"features": [
{
"id": 1,
"name": "user",
"permissions": [
{
"id": 1,
"name": "add"
},
{
"id": 2,
"name": "edit"
},
{
"id": 3,
"name": "remove"
},
{
"id": 4,
"name": "view"
}
]
},
{
"id": 2,
"name": "device",
"permissions": [
{
"id": 4,
"name": "view"
}
]
}
]
},
{
"id": 2,
"name": "ROLE2",
"features": [
{
"id": 1,
"name": "user",
"permissions": [
{
"id": 4,
"name": "view"
}
]
},
{
"id": 2,
"name": "device",
"permissions": [
{
"id": 4,
"name": "view"
}
]
}
]
}
]
But i cant write the serializer correctly?
Any help is appreciated.
I guess you should use this code, maybe there is different field_names
class PermisionSerializer(serializers.ModelSerializer):
class Meta:
model = Permission
fields = ('name', )
class FeatureSerializer(serializers.ModelSerializer):
permissions = PermisionSerializer(many=True)
class Meta:
model = Feature
fields = ('name', 'permissions', )
class RoleSerializer(serializers.ModelSerializer):
features = FeatureSerializer(many=True)
class Meta:
model = Role
fields = ('name', 'features', )

how to access child entire record in parent model in django rest framework

I am new to Django rest framework.i am trying to get child model records to the parent model as a field so that all the RefreshmentImage models records are available in games_sports list.i have posted sample code.
model.py
class Refreshment(models.Model):
title = models.CharField(max_length=200, unique=True)
type = models.CharField(max_length=200)
charges = models.DecimalField(max_digits=12, decimal_places=2, help_text="Charges per hour")
class RefreshmentImage(models.Model):
refreshment = models.ForeignKey(Refreshment, on_delete=models.CASCADE)
image = models.FileField(upload_to="refreshment_image/", null=True, blank=True)
serializers.py
class EntertainmentSerializer(serializers.ModelSerializer):
class Meta:
model = Refreshment
fields = '__all__'
class RefreshmentImageSerializer(serializers.ModelSerializer):
refreshment = EntertainmentSerializer(read_only=True, many=True)
class Meta:
model = RefreshmentImage
fields = '__all__'
views.py
def all_games_sports(request):
entertainment = Refreshment.objects.all()
serialize = EntertainmentSerializer(instance=entertainment,many=True)
serial = RefreshmentImageSerializer(instance=entertainment,many=True)
main = {'status': True, 'code': CODE_SUCCESSFUL, 'msg': SUCCESS, 'games_sports': serialize.data,'image':serial.data}
return HttpResponse(json.dumps(main), content_type='application/json')
what i got is like:
games_sports": [
{
"id": 1,
"title": "yyy",
"type": 1,
"charges": "500.00",
},
{
"id": 2,
"title": "xxxxx",
"type": "something",
"charges": "501.00",
}
*******
],
"image": [
{
"id": 1,
"image": null,
"date_created": "2019-03-03T08:16:15.538024+05:30"
},
**********
]
i want it to be:
games_sports": [
{
"id": 1,
"title": "yyy",
"type": 1,
"charges": "500.00",
"image": [
{
"id": 1,
"image": image_path,
"date_created": "2019-03-03T08:16:15.538024+05:30"
},
}
***********
],
Try this snippet
#serializers.py
"""I've re-arranged the order of 'RefreshmentImageSerializer' serializer and 'EntertainmentSerializer' serializer"""
class RefreshmentImageSerializer(serializers.ModelSerializer):
class Meta:
model = RefreshmentImage
fields = '__all__'
class EntertainmentSerializer(serializers.ModelSerializer):
image = RefreshmentImageSerializer(many=True, source='refreshmentimage_set')
class Meta:
model = Refreshment
fields = '__all__'
# views.py
"""Added DRF stuffs such as 'api_view' and 'Response'"""
from rest_framework.decorators import api_view
#api_view()
def all_games_sports(request):
entertainment = Refreshment.objects.all()
serialize = EntertainmentSerializer(instance=entertainment, many=True)
main = {'status': True, 'code': "CODE_SUCCESSFUL", 'msg': "SUCCESS", 'games_sports': serialize.data}
return Response(main)
{
"status": true,
"code": "CODE_SUCCESSFUL",
"msg": "SUCCESS",
"games_sports": [
{
"id": 1,
"image": [
{
"id": 1,
"image": null,
"refreshment": 1
},
{
"id": 3,
"image": "refreshment_image/jpg-icon.png",
"refreshment": 1
}
],
"title": "t1",
"type": "tt1",
"charges": "123.00"
},
{
"id": 2,
"image": [
{
"id": 2,
"image": "refreshment_image/asd.jpg",
"refreshment": 2
}
],
"title": "t2",
"type": "tt2",
"charges": "321.00"
},
{
"id": 3,
"image": [
{
"id": 4,
"image": "refreshment_image/Screenshot_from_2018-10-26_16-32-41.png",
"refreshment": 3
},
{
"id": 5,
"image": "refreshment_image/twitter.png",
"refreshment": 3
}
],
"title": "t3",
"type": "tt3",
"charges": "754.00"
}
]
}
What I've done here?
re-arranged the order of serializer to avoid not defined errors
added a new field in EntertainmentSerializer class to show the images associated with the Refreshment object
In views.py I've added DRF pieces of stuff, which is more suitable
References
#api_view() decorator
DRF's Response() class
DRF Nested Serializers
The source keyword argument
Hope this helps!!

Sqlalchemy - Create a row when i put a model nested with marshmallow

I trying to put a nested model and it's works, but i can see a new row in my database created in the same time.
api/program.py:
#app.route("/programs/<id>", methods=["PUT"])
def update_program(id):
program = Program.query.filter_by(id=id).first()
res = program_nested_schema.load(request.json)
program.name = res.data.name
program.steps = res.data.steps
program.updated_at = datetime.utcnow()
db.session.add(program)
db.session.commit()
return program_nested_schema.jsonify(program)
(i think it's a problem with my nested schema)
schemas:
class ProgramNested(ma.ModelSchema):
class Meta:
model = Program
fields = ('name', 'visibility', 'steps')
steps = fields.Nested(ProgramStepsSchema, many=True)
program_nested_schema = ProgramNested()
class ProgramStepsSchema(ma.ModelSchema):
class Meta:
model = Step
exercise = fields.Nested(GetExerciseSchema, many=False, only=('id',))
class GetExerciseSchema(ma.ModelSchema):
class Meta:
model = Exercise
fields = ('id', 'name', 'image', 'visibility')
In addition to the update, a line is created when I send this body:
{
"id": 2,
"name": "Jambes",
"steps": [
{
"exercise": {
"id": 6,
"image": "pompe.jpg",
"name": "Pompes"
},
"id": 6,
"position": 1,
"repetitions": 200,
"rest": 30,
"rest_end": 60,
"series": 3,
"weight": 0
},
{
"exercise": {
"id": 7,
"image": "10763352.jpg",
"name": "Squats"
},
"id": 70,
"position": 2,
"repetitions": 11,
"rest": 45,
"rest_end": 90,
"series": 4,
"weight": 16
}
],
"visibility": "PRIVATE"
}
It's my first post, teel me if you need more information and I'm sorry for my very aproximative english

Django rest framework, translate model with django-hvad

I have model Product:
class Product(TranslatableModel):
name = models.CharField(max_length=255, unique=True)
translations = TranslatedFields(
description=models.TextField(),
)
and in administration on product detail I have tabs with languages. For example tabs EN, CZ, each includes disctiption. So PUT request looks like:
{
'product': '1',
'id': 1,
'name': 'Name',
'translations': {
'cz': {'desctiption': 'Description cz'},
'en': {'desctiption': 'Description en'}
}
}
I founded in django-hvad TranslationsMixin that allows me to do that request.
in serializers I have:
class ProductTranslationSerializer(serializers.ModelSerializer):
class Meta:
exclude = ['description']
class ProductSerializer(TranslationsMixin, serializers.ModelSerializer):
class Meta:
model = Product
translations_serializer = ProductTranslationSerializer
fields = (
'name',
'description',
)
Question is how will looks ModelViewSet for this request? Can I choose language like 'language_code=en', filter that query and get something like:
[
{
id: 1
name: "name"
descritpion: "descritpion"
},
....
]
Thank you!
the most likely way i achieve is:
models.py
class Product(TranslatableModel):
category = models.ForeignKey('product.ProductCategory',
related_name='product_category',
null=True,
on_delete=models.SET_NULL,
verbose_name=u'category')
cover = models.ImageField(upload_to=product_cover,
null=True,
verbose_name=u'cover')
translations = TranslatedFields(
title=models.CharField(max_length=100,
null=True,
verbose_name=u'title'),
summary=models.TextField(null=True,
verbose_name=u'summary'),
model=models.CharField(max_length=255,
null=True,
blank=True,
verbose_name=u'model'),
price=models.DecimalField(default=0.00,
max_digits=10,
decimal_places=2,
blank=True,
validators=[MinValueValidator(0)],
verbose_name=u'price'),
content=models.TextField(verbose_name=u'content'),
publish_time=models.DateTimeField(default=timezone.now,
verbose_name=u'发布publish_time')
)
view_times = models.IntegerField(default=0,
verbose_name=u'view_times ')
views.py
class ProductViewSet(ModelViewSet):
serializer_class = ProductListSerializer
def get_queryset(self):
if 'language_code' in self.request.GET:
language_code = self.request.GET.get('language_code')
queryset = Product.objects.language(language_code).order_by('-id')
else:
queryset = Product.objects.language().order_by('-id')
return queryset
serializers.py
class ProductCategorySerializer(TranslatableModelSerializer):
class Meta:
model = ProductCategory
fields = '__all__'
class ProductListSerializer(TranslatableModelSerializer):
category = ProductCategorySerializer(read_only=True)
class Meta:
model = Product
exclude = ['is_abandon', 'content', ]
urls.py
from rest_framework import routers
router = routers.DefaultRouter()
router.register(r'product', ProductViewSet, base_name='api-product')
...
result:
http://192.168.1.108/api/product/?language_code=zh-hans you get:
{
"count": 1,
"page_num": 1,
"page_no": 1,
"next": "",
"previous": "",
"results": [
{
"id": 2,
"category": {
"id": 2,
"create_time": "2017-08-10 16:49:41",
"update_time": "2017-08-18 08:56:02",
"name": "测试",
"language_code": "zh-hans"
},
"create_time": "2017-08-18 08:53:46",
"update_time": "2017-08-18 08:56:28",
"cover": "http://192.168.1.108/media/product/20170818-085346-518_59.jpg",
"view_times": 0,
"title": "标题",
"summary": "简介",
"model": null,
"price": "90.00",
"publish_time": "2017-08-18 08:53:00",
"language_code": "zh-hans"
}
]
}
http://192.168.1.108/api/product/?language_code=en you get:
{
"count": 1,
"page_num": 1,
"page_no": 1,
"next": "",
"previous": "",
"results": [
{
"id": 2,
"category": {
"id": 2,
"create_time": "2017-08-10 16:49:41",
"update_time": "2017-08-18 08:56:02",
"name": "测试",
"language_code": "zh-hans"
},
"create_time": "2017-08-18 08:53:46",
"update_time": "2017-08-18 09:00:23",
"cover": "http://192.168.1.108/media/product/20170818-085346-518_59.jpg",
"view_times": 0,
"title": "title",
"summary": "summary",
"model": "model",
"price": "91.00",
"publish_time": "2017-08-18 08:56:04",
"language_code": "en"
}
]
}
this way fk will not change language,if you want fk change language too,use:
urls.py
urlpatterns += i18n_patterns(
'''
url(r'^api/', include(router.urls)),
prefix_default_language=False,
)
change language by
http://192.168.1.108/zh-hans/api/product/
to
http://192.168.1.108/en/api/product/
your will get:
{
"count": 1,
"page_num": 1,
"page_no": 1,
"next": "",
"previous": "",
"results": [
{
"id": 2,
"category": {
"id": 2,
"create_time": "2017-08-10 16:49:41",
"update_time": "2017-08-18 08:56:02",
"name": "test",
"language_code": "en"
},
"create_time": "2017-08-18 08:53:46",
"update_time": "2017-08-18 09:00:23",
"cover": "http://192.168.1.108/media/product/20170818-085346-518_59.jpg",
"view_times": 0,
"title": "title",
"summary": "summary",
"model": "model",
"price": "91.00",
"publish_time": "2017-08-18 08:56:04",
"language_code": "en"
}
]
}
Answer from owner of django-hvad github repo #spectras:
If I understand well, you want to use a different serialized form for the collection endpoint and the item endpoint. That is, GET-1, PUT, POST would use the translations mixin, while GET-many would not.
You need two have two different serializers for this:
The one you created
another one that would be, for instance,
class ProductItemSerializer(TranslatableModelSerializer): ...
another one that would be, for instance,
class ProductItemSerializer(TranslatableModelSerializer): ...
Given that, you can add to your ModelViewSet a method that dynamically chooses the serializer class depending on request type:
class SomeModelViewSet(ModelViewSet):
# serializer_class = not needed, we use the method instead
def get_serializer_class(self):
if self.action == 'list':
return ProductItemSerializer
return ProductSerializer
An alternate method, perhaps easier to use on the Javascript side, would be to make 2 viewsets for the Product model, a read-write one being translation aware (using ProductSerializer) and a read-only one not translation aware, using (ProductItemSerializer).
In the same vein, I usually only have translation-unaware serializers and add a /api/product/details/ endpoint that is translation-aware. This way, I only have to handle the complexity of a dict object when going into edit/detailed mode on the client side.

Django Rest Framework & Entity–attribute–value model (EAV) Data Model

from django.db import models
# django user
from django.contrib.auth.models import User
class Entity(models.Model):
"""
Entity of EAV
"""
entity = models.CharField(max_length=216,
null=False, default='entity_name',
name='entity', verbose_name='Entity of EAV',
db_index=True,
unique=True
)
class Asset(models.Model):
"""
Asset of EAV
"""
asset = models.CharField(max_length=216, null=False,
default='asset', name='asset',
verbose_name='Asset of EAV'
)
entity = models.ForeignKey(to=Entity)
class Meta:
unique_together = ("asset", "entity")
class Value(models.Model):
"""
Value of EAV
"""
value = models.CharField(max_length=216,
null=False, default='value',
name='value', verbose_name='Value of EAV'
)
asset = models.ForeignKey(to=Asset)
owner = models.ForeignKey(User, verbose_name='EAV Owner', related_name='eav')
class Meta:
unique_together = ('value', 'asset', 'owner')
Serializers
class EntitySerializer(serializers.Serializer):
id = serializers.IntegerField(label='ID', read_only=True)
entity = serializers.CharField(label='Entity of EAV', max_length=216, required=False)
class AssetSerializer(serializers.Serializer):
id = serializers.IntegerField(label='ID', read_only=True)
asset = serializers.CharField(default='asset', label='Asset of EAV', max_length=216)
entity = EntitySerializer(read_only=True)
class ValueSerializer(serializers.Serializer):
id = serializers.IntegerField(label='ID', read_only=True)
value = serializers.CharField(default='value', label='Value of EAV', max_length=216)
asset = AssetSerializer(read_only=True)
owner = UserModelSerializer(read_only=True)
class EntityAssetValueSerializer(serializers.Serializer):
entity = EntitySerializer(many=True)
asset = AssetSerializer(many=True)
value = ValueSerializer(many=True)
Expected Serialization
{
"entities": [
{
"entity": "Hero",
"id": 1,
"owner": {
"name": "BatMan",
"id": "1"
},
"groups": [
{
"id": "1",
"name": "SuperHeroes Group"
}
],
"asset": [
{
"asset": "Name",
"value": "BatMan",
"asset_id": 1,
"value_id": 1
},
{
"asset": "Age",
"value": "30",
"asset_id": 1,
"value_id": 2
}
]
},
{
"entity": "Hero",
"id": 1,
"owner": {
"name": "SuperMan",
"id": "2"
},
"groups": [
{
"id": "1",
"name": "SuperHeroes Group"
}
],
"asset": [
{
"asset": "Name",
"value": "SuperMan",
"asset_id": 1,
"value_id": 3
},
{
"asset": "Age",
"value": "30",
"asset_id": 1,
"value_id": 4
}
]
},
{
"entity": "Villian",
"id": 1,
"owner": {
"name": "Joker",
"id": "3"
},
"groups": [
{
"id": "2",
"name": "SuperVillians Group"
}
],
"asset": [
{
"asset": "Name",
"value": "Joker",
"asset_id": 3,
"value_id": 4
},
{
"asset": "Age",
"value": "30",
"asset_id": 4,
"value_id": 5
}
]
},
{
"entity": "Person",
"id": 1,
"owner": {
"name": "Puny Human",
"id": "3"
},
"groups": [
{
"id": "2",
"name": "Humans Group"
}
],
"asset": [
{
"asset": "Name",
"value": "Human Being",
"asset_id": 5,
"value_id": 6
},
{
"asset": "Age",
"value": "30",
"asset_id": 6,
"value_id": 7
}
]
}
]
}
Achieved Serialization
{
"eav": [
{
"id": 1,
"value": "Human",
"asset": {
"id": 1,
"asset": "Name",
"entity": {
"id": 1,
"entity": "Human"
}
},
"owner": {
"id": 1,
"username": "PunyHuman"
}
},
{
"id": 2,
"value": "26",
"asset": {
"id": 2,
"asset": "Age",
"entity": {
"id": 1,
"entity": "Human"
}
},
"owner": {
"id": 1,
"username": "PunyHuman"
}
},
{
"id": 3,
"value": "26",
"asset": {
"id": 3,
"asset": "Age",
"entity": {
"id": 2,
"entity": "Hero"
}
},
"owner": {
"id": 2,
"username": "BatMan"
}
},
{
"id": 4,
"value": "BatMan",
"asset": {
"id": 3,
"asset": "Name",
"entity": {
"id": 2,
"entity": "Hero"
}
},
"owner": {
"id": 2,
"username": "BatMan"
}
},
{
"id": 5,
"value": "26",
"asset": {
"id": 3,
"asset": "Age",
"entity": {
"id": 2,
"entity": "Hero"
}
},
"owner": {
"id": 3,
"username": "SuperMan"
}
},
{
"id": 6,
"value": "SuperMan",
"asset": {
"id": 4,
"asset": "Name",
"entity": {
"id": 2,
"entity": "Hero"
}
},
"owner": {
"id": 3,
"username": "SuperMan"
}
}
]
}
API View
class EntityAssetValueAPIView(APIView):
queryset = Value.objects.select_related('asset', 'asset__entity', 'owner')
serializer_class = ValueSerializer
# If you want to use object lookups other than pk, set 'lookup_field'.
# For more complex lookup requirements override `get_object()`.
lookup_field = 'pk'
# lookup_url_kwarg = None
# The filter backend classes to use for queryset filtering
# filter_backends = api_settings.DEFAULT_FILTER_BACKENDS
# The style to use for queryset pagination.
# pagination_class = api_settings.DEFAULT_PAGINATION_CLASS
# def allowed_methods(self):
# http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
# return http_method_names
def get(self, request, *args, **kwargs):
eav = self.queryset.all()
serializer = self.serializer_class(eav, many=True)
return Response(serializer.data)
What I want to do is, Get all the ENTITIES Assigned to a USER ( along with the ASSET & VALUES ).
The same data is posted for a NEW ENTITY ASSIGNMENT to USER .
From What I understood from DRF, I would need an API view, API view would call serializer, so, I would have to create a custom Serializer, then to save the data I have to override create method, where in I will have these separate serializers that would validate the data and save it.
I am not able to send the desired RESPONSE or ingest the REQUEST coming in.
What should be a way forward ?
I have faced the similar problem So I'll explain a little scenario here. So you can take reference from that.
Added some related names in models :
class Asset(models.Model):
"""
Asset of EAV
"""
asset = models.CharField(max_length=216, null=False,
default='asset', name='asset',
verbose_name='Asset of EAV'
)
entity = models.ForeignKey(to=Entity, related_name='asset_entity')
class Value(models.Model):
"""
Value of EAV
"""
value = models.CharField(max_length=216,
null=False, default='value',
name='value', verbose_name='Value of EAV'
)
asset = models.ForeignKey(to=Asset, related_name='asset_value')
owner = models.ForeignKey(User, verbose_name='EAV Owner', related_name='eav')
initial queryset looks like this, the idea is to fetch all information that is required initially:
queryset = Entity.objects.filter('**condition comes here**')
.values('id', 'entity', 'asset_entity', 'asset_entity__asset', 'asset_entity__asset_value', 'asset_entity__asset_value__value',
'asset_entity__asset_value__owner_id',)
Pass this queryset when trying to make response :
serializer = serializer(queryset, many=True, context={'request': request})
Serailizers :
class Owner_Serializer(serializers.ModelSerializer)
class Meta:
model = User
exclude = ('**exclude fields you want to exclude**', )
class EntitySerializer(serializers.Serializer):
id = serializers.IntegerField(source='id')
entity = serializers.CharField(source='entity')
owner = serializers.SerializerMethodField()
groups = serializers.SerializerMethodField()
asset = serializers.SerializerMethodField()
def get_owner(self, obj):
return Owner_Serializer(obj.get('asset_entity__asset_value__owner_id'), context=self.context).data
Same process goes for groups and asset fields.
in get_owner() we have entity object and from that object we can get owner_id , as we have already fetched related data initially.
So the main idea here to fetch all data initially and then serilaize that data according to your requirement.
Existing Nested Serailization do not support the response format you required.
Note : Initial querset is vry important , you may need to use prefetch related there because we are fetching data using reverse relationship. Also I didn't test the queryset so have to make sure that correct related_names are used to fetch related data.

Categories

Resources