Scalarize a nested field using marshmallow - python-3.x

I have two Database Models like this
class Setting(db.Model):
id = db.Column(db.Integer, id=True)
container_id = ST_db.Column(ST_db.Integer, db.ForeignKey('settings_container.id'))
setting_name = ST_db.Column(ST_db.String(50))
setting_value = ST_db.Column(ST_db.String(50))
class SettingsContainer(db.Model):
id = db.Column(db.Integer, id=True)
settings = db.relationship('Settings', backref='container', cascade='all, delete')
When I serialize the model SettingsContainer using the following schemas
class Setting(ma.Schema):
class Meta:
fields = (
'setting_name',
'setting_value',
)
class SettingsContainer(ma.Schema):
settings = ST_ma.Nested(Setting, many=True)
class Meta:
fields = (
'id',
'settings'
)
What I get is
[
{
"id": 1
"settings": [
{
"setting_name": 'name1',
"setting_value": 'value1'
},
{
"setting_name": 'name2',
"setting_value": 'value2'
},
}
"id": 2
"settings": [
{
"setting_name": 'name3',
"setting_value": 'value3'
},
{
"setting_name": 'name4',
"setting_value": 'value4'
},
]
But I want to get data in the format of
[
{
"id": 1
"settings": [['name1', 'value1'], ['name2', 'value2']]
}
{
"id": 2
"settings": [['name3', 'value3'], ['name4', 'value4']]
}
]
I want to able to extract the Nested fields, I don't understand how to do it using the ma.Function method, thanks a lot to everyone in advance.

Okay so I found out the answer, what I have to do is to use ma.Function with ma.Pluck
The appropriate serializers are.
class Setting(ma.Schema):
complete_setting = ma.Function(lambda setting:(
setting.setting_name,
setting.setting_value,
))
class SettingsContainer(ma.Schema):
settings = ma.List(ma.Pluck(Setting, 'complete_setting'))
class Meta:
fields = (
'id',
'settings'
)

Related

Nested serializer representation for PrimaryKeyRelatedField

I want to add and remove products to an order by only using their ids, but I want the order representation to look like a nested serializer.
My Models:
class Product(models.Model):
title = models.CharField(max_length=200)
price = models.DecimalField(max_digits=1_000, decimal_places=2)
def __str__(self):
return self.title
class Order(models.Model):
date = models.DateField()
products = models.ManyToManyField(Product, blank=True, related_name='orders')
My Serializers:
class ProductSerializer(serializers.ModelSerializer):
price = serializers.DecimalField(max_digits=1_000,
decimal_places=2,
coerce_to_string=False)
class Meta:
model = Product
fields = ['id', 'title', 'price']
class OrderSerializer(serializers.ModelSerializer):
products = serializers.PrimaryKeyRelatedField(queryset=Product.objects.all(), many=True)
class Meta:
model = Order
fields = ['id', 'date', 'products']
I'm trying to get the below representation:
{
"id": 1,
"date": "2021-08-12",
"products": [
{
"id": 1,
"title": "Item 1",
"price": 19.99
},
{
"id": 3,
"title": "Item 3",
"price": 49.99
}
]
}
However, if I want to create the above order the json should look like this:
{
"date": "2021-08-12",
"products":[1, 3]
}
And if I want to add a product with id==2 to the above order it should look like this:
{
"id": 1,
"date": "2021-08-12",
"products":[1, 3, 2]
}
I've tried overriding the to_representation() method and adding a nested serializer there, but I have no idea how to go about it. Should it look something like this, or am I going in a completely wrong direction here?
def to_representation(self, instance):
data = super().to_representation(instance)
data['products'] = ProductSerializer(data=instance['products'])
return data
Ended up fixing it with the to_representation() method. I don't know if this is the best way to do it, but it works for now.
def to_representation(self, instance):
data = super().to_representation(instance)
products_list = []
for product_id in data['products']:
product = instance.products.get(pk=product_id)
products_list.append(
{
'id': product.id,
'title': product.title,
'price': product.price
}
)
data['products'] = products_list
return data
use Nested Serializer Relationships.
and your OrderSerializer serializer class will be like this:
class OrderSerializer(serializers.ModelSerializer):
products = ProductSerializer(many=True)
class Meta:
model = Order
fields = ['id', 'date', 'products']

How to resolve multiple querysets in graphene.Union?

I want to create a graphene.Union type of multiple existing types. I am able to resolve it but it is not in my required format.
Schema
from graphene_django import DjangoObjectType
class ageType(DjangoObjectType):
class Meta:
model = age
class ethnicityType(DjangoObjectType):
class Meta:
model = ethnicity
class combinedType(graphene.Union):
class Meta:
types = (ageType, ethnicityType)
class Query(graphene.ObjectType):
defaultPicker = graphene.List(combinedType)
def resolve_defaultPicker(self, info):
items = []
age_q = age.objects.all()
items.extend(age_q)
ethnicity_q = ethnicity.objects.all()
items.extend(ethnicity_q)
return items
The query I am using in the graphql admin:
{
defaultPicker{
... on ageType{
id
age
}
... on ethnicityType{
id
ethnicity
}
}
}
I want to get a output like this:
{
"data": {
"defaultPicker": [
'ageType': [{
"id": "2",
"ethnicity": "American",
"ethnicityFr": "Test"
}],
'ethnicityType': [{
"id": "1",
"familyPlans": "3 kids",
"familyPlansFr": "3 enfants"
}],
]
}
}
I tried many things but couldn't find a way to resolve it.

Adding Custom Page fields wagtail api returning empty array for related field

Following the doc at Adding custom page fields, im trying to add Todo's to a Task object/page model for them to be queryable via the api (same thing for todos, make parent Task queryable), however, the related field always returns an empty array (I would have expected the related (parent or child) Pages to be in the response:
class Task(Page):
CHOICES = [(i, i) for i in range(11)]
sub_order = models.IntegerField(default=1, choices=CHOICES)
content_panels = Page.content_panels + [
...
]
api_fields = [
APIField('title'),
APIField('todos'),
]
class Todo(Page):
CHOICES = [(i, i) for i in range(1, 11)]
sub_order = models.IntegerField(default=1, choices=CHOICES)
parent_page_types = ['app.Task']
page = models.ForeignKey('app.Task', on_delete=models.SET_NULL, null=True, blank=True, related_name='todos')
content_panels = Page.content_panels + [
...
]
api_fields = [
APIField('parent_page_types'),
APIField('sub_order'),
]
endpoint: .../api/v2/pages/?format=json&type=app.Task&fields=*
Response:
{
"meta": {
"total_count": 1
},
"items": [
{
"id": 18,
"meta": {
"type": "app.Task",
"detail_url": ".../api/v2/pages/18/",
"html_url": "theURL",
"slug": "aasdasdsad",
"show_in_menus": false,
"seo_title": "",
"search_description": "",
"first_published_at": "2019-02-05T14:13:09.596817Z"
},
"title": "aasdasdsad",
"parent_page_types": [
"app.ParentPageType"
],
"sub_order": 1,
"todos": [] <-------- EMPTY ?
}
]
}
UPDATE:
the sqlite db doesn't seem to be creating/adding the todos or tasks in the table when I create the records =/ . The field is showing up as null, still troubleshooting

Not able to pass last inserted_id from parent serializer to children serializer with Django restframework

I am trying to save parent (VisVisits) and children (VisVistiData) table with same api call. Data is coming into json format. I am able to save both the table except one column visit_id in the children (VisVisitData) table. visit_id does not come from the json. It is auto number type field in parent table(VisVisits) and I want to take visit_id from parent(after gets insert) table and save it to their children ids with other column in children table (VisVisitData)
I really need help to fix this issue.
Serializer
class VisVisitsSerializer(serializers.ModelSerializer):
data = VisVisitDataSerializer(many=True)
class Meta:
model = VisVisits
fields = ('visit_id','user','data')
read_only_fields = ['visit_id']
def create(self, validated_data):
visits_data = validated_data.pop('data')
visit = VisVisits.objects.create(**validated_data)
for visit_data in visits_data:
VisVisitData.objects.create(visit_id=visit.visit_id, **visit_data)
return visit
class VisVisitDataSerializer(serializers.ModelSerializer):
class Meta:
model = VisVisitData
fields = ('__all__')
model
class VisVisits(models.Model):
visit_id = models.IntegerField(primary_key=True,auto_created=True)
user = models.ForeignKey(UsrUsers, models.DO_NOTHING, blank=False, null=False)
def __str__(self):
return str(self.visit_id)
class VisVisitData(models.Model):
vdata_id = models.IntegerField(primary_key=True,auto_created=True)
visit = models.ForeignKey('VisVisits', models.DO_NOTHING, blank=True, null=True, related_name='data')
def __str__(self):
return str(self.vdata_id)
json
{
"user": "1",
"visits": [
{
"action": "i",
"local_id": "170",
"data": [
{
"Active": "1",
"LocalID": "1905",
"VisitDataID": "",
},
{
"Active": "1",
"LocalID": "1906",
"VisitDataID": "",
},
{
"Active": "1",
"LocalID": "1907",
"VisitDataID": "",
},
{
"Active": "1",
"LocalID": "1908",
"VisitDataID": "",
},
{
"Active": "1",
"LocalID": "1909",
"VisitDataID": "",
}
]
}

flask-marshmallow custom fields

I use flask-marshmallow and mongoengine.
Also flask-restplus for my API server.
Here is my api.py
class BoardSchema(ma.Schema):
class Meta:
fields = ('no', 'title', 'body', 'tags', 'created_at', 'views')
board_schema = BoardSchema()
boards_schema = BoardSchema(many=True)
class ArticleList(Resource):
def get(self):
articles = Board.objects.all()
return boards_schema.jsonify(articles)
model.py
from datetime import datetime
from mongoengine import *
from config import DB_NAME
connect(DB_NAME)
class Board(Document):
d = datetime.now()
date = "{}-{}-{}".format(d.year, d.month, d.day)
no = SequenceField()
title = StringField(required=True)
body = StringField(required=True)
tags = ListField(StringField())
likes = ListField(StringField())
views = ListField(StringField())
password = StringField(required=True)
created_at = DateTimeField(default=date)
updated_at = DateTimeField(default=date)
When I access to /article, it's result like this ->
{
"body": "123",
"created_at": "2018-08-20T00:00:00+00:00",
"no": 1,
"tags": [
"MySQL",
"C"
],
"title": "\ud14c\uc2a4\ud2b8",
"views": [
"127.0.0.1"
]
}
in "views", ip will be added who read article.
But I want to count of all the list of views and include it to my result.
The result I wanted is here.
{
"body": "123",
"created_at": "2018-08-20T00:00:00+00:00",
"no": 1,
"tags": [
"MySQL",
"C"
],
"title": "\ud14c\uc2a4\ud2b8",
"views": 20
}
I'm new at flask-marshmallow so I'm so confused how can I solve this issue.
Thanks.
Maybe you can try like this:
class BoardSchemaCustom(ma.ModelSchema):
class Meta:
model = Board
views = ma.fields.method(deserialize="_custom_serializer")
def _custom_serializer(self, obj):
return len(obj.views)
Create instance of your custom schema:
custom_board_schema = BoardSchemaCustom()
and dump it:
dump, errors = custom_board_schema.schema.dump(Board.query.first())
>>> dump
i've got the same problem. and my code works after installing marshmallow-sqlalchemy
pip install marshmallow-sqlalchemy
see from offical documentation
https://flask-marshmallow.readthedocs.io/en/latest/
Below snippet would also work:
class BoardSchemaCustom(ma.ModelSchema):
class Meta:
model = Board
views = ma.fields.Function(lambda obj: len(obj.views))

Resources