Flask API - create nested json response group by field single table - python-3.x

I have a basic API setup to do a basic Post and Get from a single table. I want to create a nested array though grouping by force_element_type
model.py
from db import db
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy import text as sa_text
class ForceElementModel(db.Model):
__tablename__ = 'force_element'
__table_args__ = {'schema': 'force_element'}
force_element_id = db.Column(UUID(as_uuid=True), primary_key=True, server_default=sa_text("uuid_generate_v4()"))
name = db.Column(db.String(100), nullable=False)
force_element_type = db.Column(db.String(20), nullable=False)
def __init__(self, name, force_element_type):
self.name = name
self.force_element_type = force_element_type
def json(self):
return {'name': self.name, 'force_element_type': self.force_element_type}
#classmethod
def find_by_name(cls, name):
return cls.query.filter_by(name=name).first() # simple TOP 1 select
def save_to_db(self): # Upserting data
db.session.add(self)
db.session.commit() # Balla
def delete_from_db(self):
db.session.delete(self)
db.session.commit()
resource.py
from flask_restful import Resource, reqparse
#from flask_jwt import jwt_required
from models.force_element import ForceElementModel
class ForceElement(Resource):
parser = reqparse.RequestParser() # only allow price changes, no name changes allowed
parser.add_argument('force_element_type', type=str, required=True, help='This field cannot be left blank')
##jwt_required()
def post(self, name):
if ForceElementModel.find_by_name(name):
return {'message': "An Force Element with name '{}' already exists.".format(name)}, 400
data = ForceElement.parser.parse_args()
force_element = ForceElementModel(name, data['force_element_type'])
try:
force_element.save_to_db()
except:
return {"message": "An error occurred inserting the item."}, 500
return force_element.json(), 201
class ForceElementList(Resource):
##jwt_required()
def get(self):
return {'force_elements': [force_element.json() for force_element in ForceElementModel.query.all()]}
class ForceElementType(Resource):
##jwt_required()
def get(self):
The GET endpoint using ForceElementList returns
{
"force_elements": [
{
"name": "San Antonio",
"force_element_type": "ship"
},
{
"name": "Nimitz",
"force_element_type": "ship"
},
{
"name": "Nimitz- Starboard",
"force_element_type": "Crew"
},
{
"name": "Nimitz- Port",
"force_element_type": "Crew"
}
]
}
I don't know how to group by force_element_type and return
[
"ship": [
{
"name": "San Antonio",
"force_element_id": "xxx1"
},
{
"name": "Nimitz",
"force_element_id": "xxx2"
}],
"crew": [
{
"name": "Nimitz- Starboard",
"force_element_id": "yyy1"
},
{
"name": "Nimitz- Port",
"force_element_id": "yyy2"
}
]
]
How do I create this separate andpoint?

OK I got there, here is how I did it. Is there a better way?
Lesson one use an online parser to check the json format this is what I was actually aiming for and the square braket at then start had me scratching my head for a while
{
"ship": [
{
"name": "San Antonio",
"force_element_id": "xxx1"
},
{
"name": "Nimitz",
"force_element_id": "xxx2"
}],
"crew": [
{
"name": "Nimitz- Starboard",
"force_element_id": "yyy1"
},
{
"name": "Nimitz- Port",
"force_element_id": "yyy2"
}]
}
This code creates the correct format for the output
class ForceElementType(Resource):
##jwt_required()
def get(self):
types = {}
force_elements = ForceElementModel.query.order_by(ForceElementModel.force_element_type.desc()).all()
for force_element in force_elements:
nested = {'name': force_element.name, 'force_element_id': str(force_element.force_element_id)}
print(nested)
if not force_element.force_element_type in types:
types[force_element.force_element_type] = []
types[force_element.force_element_type].append(nested)
response = types

Related

How to Updating JSONField in Django?

I'll give coffee to the person who found the solution Help me please. Query object:The result I want is just to update the value of auth_token
My model:
class Student(models.Model):
name = models.CharField(max_length=100, null=True, blank=True)
age = models.IntegerField(null=True, blank=True)
configuration=models.JSONField(null=True)
def __str__(self):
return self.name
Query object:The result I want is just to update the value of auth_token
class Bank:
def example(self):
query = Student.objects.get(id=1)
el =query.configuration
encoded_hand = json.dumps(el)
jsonObject = json.loads(encoded_hand)
for value in jsonObject:
checkValue=value['name']
if checkValue == 'Auth_token':
backUrl= value['value']
backUrl = "token"
query.configuration = backUrl # This is not working properly. Bad idea
query.save()
print("Ene bol:{}".format(backUrl))
MyJson :
[
{
"name": "Auth_token",
"value": "sfsdf"
},
{
"name": "Refresh_token",
"value": "sdfsdfs" # How to update this value token ?
},
{
"name": "BaseUrl",
"value": "test"
}
]

Has an invalid foreign key Django TestCase

i have a model pruchase and a model transaction, transactions have a ForeignKey from pruchase and when a try run the tests success th first test_payment_request but the second test_payment_transaction_state faile an launch the next error:
django.db.utils.IntegrityError: The row in table 'transactions_transactionmodel' with primary key '0664aefce71447699d8ca9e7677ba4cc' has an invalid foreign key: transactions_transactionmodel.purchase_id contains a value 'ba7dc5ac0e1c4b9eb009e772f405f5db' that does not have a corresponding value in purchases_purchasemodel.id.
this is my test:
import datetime
import socket
from django.test import TestCase
from .payment import PaymentTransactions
from apps.purchases.models import PurchaseModel
class PaymentTransactionsTestCase(TestCase):
def setUp(self):
self.purchase = {"purchase":PurchaseModel( total_value = 124236,
products = [
{
"name": "Aretes",
"value": "6490"
},
{
"name": "Manilla",
"value": "6.000"
}
],
purchase_date = datetime.datetime.utcnow()
),
"value":124236,
"client_ip": socket.gethostbyname(socket.gethostname())
}
def test_payment_request(self):
error, payment, transaction = PaymentTransactions().\
payment_transaction_request(**self.purchase)
self.assertFalse(error)
self.assertTrue(payment)
self.assertIn("tpaga_payment_url", payment)
self.assertIn("token", payment)
self.assertEquals(transaction.token, payment["token"])
print("paso prueba 1")
def test_payment_transaction_state(self):
purchase = {"purchase":PurchaseModel( total_value = 124236,
products = [
{
"name": "Aretes",
"value": "6490"
},
{
"name": "Manilla",
"value": "6.000"
}
],
purchase_date = datetime.datetime.utcnow()
),
"value":124236,
"client_ip": socket.gethostbyname(socket.gethostname())
}
error, payment, transaction = PaymentTransactions().\
payment_transaction_request(**purchase)
self.assertFalse(error)
error, transaction_created = PaymentTransactions().\
payment_transaction_state(transaction.id)
self.assertFalse(error)
self.assertEquals(transaction_created.state, transaction.state)
but i don't know whatshappends if someone know, please can explain me.
Make change models.SOMETHING to models.CASCADE in your field of Model Payment.

Python Dataclass (Marshmallow) : How to Handle Dynamic Response Keys

I am creating dataclass Objects for Response I get. It worked fine until, I received static key'ed Response. But not sure how to handle when the keys are dynamic. For example, below is a dataclass
#dataclass_json
#dataclass
class CollectorDetails:
items: List[Items]
total: int = None
isMin: bool = False
searchId: int = None
#property
def total_items(self):
return self.total
#property
def is_min(self):
return self.isMin
#property
def search_id(self):
return self.searchId
#property
def get_items(self):
return self.items
above is easy to parse, as items, total, isMin, searchId in the response key will never change
but for below type of response where key 44897 is dynamically generated, How do I write a dataclass ?
"byId": {
"cloudTest": {
"44897": {
"id": "44897",
"name": "test-azure",
"parentGroupId": {
"model": "resourceGroups",
"id": "1"
},
so next time if I hit the endpoint again my response is something like below
"byId": {
"cloudTest": {
"55456": {
"id": "55456",
"name": "test-azure",
"parentGroupId": {
"model": "resourceGroups",
"id": "1"
},
here the response key is now '55456'

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": "",
}
]
}

Swagger API documentation and flask-restplus: How to represent an object with a key in the body of a request

I have this example of the parameter needed in the body of a PUT request to my API:
{
"id": "string",
"closed_date": "2018-11-20T18:42:58.946Z",
"contact": "string",
"description": "string",
"status": "Open"
}
To have it represented in my Swagger end point documentation I did this :
#api.doc(body=card_change_fields)
def put(self, card_id, *args, **kwargs):
Where:
card_change_fields = api.model('card modification', {
'id': fields.String(description='id', required=True),
'closed_date': fields.DateTime(description='Closed date'),
'contact': fields.String(description='Contact'),
'description': fields.String(description='Description'),
'status': fields.String(description='Status', required=True,
enum=["Open", "Closed"])
})
However what I want is actually this :
{ card : {
"id": "string",
"closed_date": "2018-11-20T18:42:58.946Z",
"contact": "string",
"description": "string",
"status": "Open" }
}
How can I do this in my flask-restplus swagger documentation ?
I tried with child and parent model and expect with no success
Thanks,
DT
You need to use fields.Nested to use a model to be a input of another Model. Check the code below:
card_change_fields = api.model('card modification', {
'id': fields.String(description='id', required=True),
'closed_date': fields.DateTime(description='Closed date'),
'contact': fields.String(description='Contact'),
'description': fields.String(description='Description'),
'status': fields.String(description='Status', required=True,
enum=["Open", "Closed"])
})
card = api.model('Card', {
'card': fields.Nested(card_change_fields, required=True)
})
And respectively your doc rendering will also change to:
#api.doc(body=card)
def put(self, card_id, *args, **kwargs):

Resources