Python export Database query result as JSON for Calendar JS - python

I am querying my Database to then return the values and JSONIFY them into JSON format so that the "fullcalendar js" can parse them and show them on my front end.
My model of the DB is as follows :
class database(db.Model):
id = db.Column(db.Integer, primary_key=True)
userid = db.Column(db.Integer, nullable=False)
user = db.Column(db.String(200), nullable=False)
startdate = db.Column(db.String(10), nullable=False)
enddate = db.Column(db.String(10), nullable=False)
duration = db.Column(db.Integer, nullable=False)
approved = db.Column(db.Boolean, nullable=False)
The JSON format i need them to be is :
[
{
"title": "Long Event",
"start": "2014-09-07",
"end": "2014-09-10"
}
]
What i have tried ("And failed!")
alldata = database.query.filter(database.approved == True).all()
events = {"title": [], "start": [], "end": []};
for row in alldata:
events["title"].append(row.user.strip("[]"))
events["start"].append(datetime.datetime.strptime(row.startdate,'%d/%m/%Y').strftime('%Y-%m-%d').strip("[]"))
events["end"].append(datetime.datetime.strptime(row.enddate, '%d/%m/%Y').strftime('%Y-%m-%d').strip("[]"))
# Serializing json
json_object = json.dumps(events, indent=4)
jsontoreturn="["+json_object+"]"
return jsontoreturn
The reason this fails is the resulting JSON is in the format of :
[{
"title": [
"Ben"
],
"start": [
"2021-12-29"
],
"end": [
"2021-12-31"
]
}]
As you can see the Dictionary is adding Sqaure brackets and as a result the FullCalendar JS (https://fullcalendar.io/docs/events-json-feed) doesnt parse it correctly and fails.
Anyone got any ideas?

I don't have the ability to actually test this against your value for alldata but I suspect the following will work:
alldata = database.query.filter(database.approved == True).all()
def process_row(row):
# func which returns a dictionary like:
# {"title": "Long Event", "start": "2014-09-07", "end": "2014-09-10" }
return dict (title = row.user.strip("[]"),
start = datetime.datetime.strptime(row.startdate,'%d/%m/%Y').strftime('%Y-%m-%d').strip("[]"),
end = datetime.datetime.strptime(row.enddate, '%d/%m/%Y').strftime('%Y-%m-%d').strip("[]"),
)
# Make a list of dictionaries based on the input, `alldata`
events = [process_row(r) for r in alldata]
Then simply:
json_object = json.dumps(events, indent=4)
return json_object
OR, if you want to use Flask's jsonify function which also sets the Content-Type header:
return jsonify(events)

Related

How to join nested schema into one JSON object with Flask Marshmallow

I have a problem joining two schema into one nested JSON object. This API returned JSON as a result from 3 related tables join query. After i did query, i use two Marshmellow schema as referenced from here. But the response is not as expected, here is the response:
{
"message": "success",
"device": [
{
"device_name": "Kamar Tidur Utama"
}
],
"sensor": [
{
"value": 23.3683,
"sensor_name": "Temperature"
},
{
"value": 0.0,
"sensor_name": "Motion"
},
{
"value": 90.12,
"sensor_name": "Humidity"
},
{
"value": 15.8667,
"sensor_name": "Current 1"
},
{
"value": 15.0333,
"sensor_name": "Current 2"
}
]
}
What i wanted is the "sensor" object is put inside the "device". So many devices has many sensors like this:
{
"message": "success",
"device": [
{
"device_name": "Kamar Tidur Utama"
"sensor": [
{
"value": 23.3683,
"sensor_name": "Temperature"
},
{
"value": 0.0,
"sensor_name": "Motion"
},
{
"value": 90.12,
"sensor_name": "Humidity"
},
{
"value": 15.8667,
"sensor_name": "Current 1"
},
{
"value": 15.0333,
"sensor_name": "Current 2"
}
]
}
]
}
These are my three related models:
Device.py (a method that do query for API)
#classmethod
def get_device_sensor(cls):
device_sensor_schema = DeviceSensorSchema(many=True)
sensor_value_schema = SensorValueSchema(many=True)
device = Device.query.join(SensorData, Device.id == SensorData.device_id)\
.add_columns(Device.name.label('device_name'))
print(device)
sensor = Sensor.query.join(SensorData, Sensor.id == SensorData.sensor_id)\
.add_columns(Sensor.name.label('sensor_name'), SensorData.value.label('value'))
res_device = device_sensor_schema.dump(device, many=True)
res_sensor = sensor_value_schema.dump(sensor, many=True)
if device:
return jsonify({'message': 'success', 'device': res_device, 'sensor': res_sensor})
else:
return {'message': 'Table device is empty'}, 404
Device.py (two marshmellow schema)
class SensorValueSchema(ma.Schema):
sensor_name = fields.String()
value = fields.Float()
ordered=True
class DeviceSensorSchema(Schema):
device_name = fields.String()
sensors = fields.List(fields.Nested(SensorValueSchema))
Device.py (model class)
class Device(db.Model):
__tablename__ = "devices"
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
name = db.Column(db.String(255))
serial_number = db.Column(db.String(255), unique=True)
used_relay = db.Column(db.Integer, default=0)
created_at = db.Column(db.DateTime(timezone=True), server_default=db.func.now())
updated_at = db.Column(db.DateTime(timezone=True), onupdate=db.func.now())
switches = db.relationship('Switch', backref='device', lazy='dynamic')
power_usages = db.relationship('PowerUsage', backref='device', lazy='dynamic')
power_expenses = db.relationship('PowerExpense', backref='device', lazy='dynamic')
behaviors_dataset = db.relationship('BehaviorDataset', backref='device', lazy='dynamic')
usage_histories = db.relationship('UsageHistory', backref='device', lazy='dynamic')
sensors_data = db.relationship('SensorData', backref='device', lazy='dynamic')
notifications = db.relationship('Notification', backref='device', lazy='dynamic')
device_serial_number = db.relationship('DeviceSerialNumber', backref='device', lazy='dynamic')
Sensor.py (model class)
class Sensor(db.Model):
__tablename__ = "sensors"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(120))
created_at = db.Column(db.DateTime(timezone=True), server_default=db.func.now())
updated_at = db.Column(db.DateTime(timezone=True), onupdate=db.func.now())
sensors_data = db.relationship('SensorData', backref='sensor', lazy='dynamic')
SensorData.py (model class)
class SensorData(db.Model):
__tablename__ = "sensors_data"
id = db.Column(db.Integer, primary_key=True)
device_id = db.Column(db.Integer, db.ForeignKey('devices.id'))
sensor_id = db.Column(db.Integer, db.ForeignKey('sensors.id'))
value = db.Column(db.Float)
created_at = db.Column(db.DateTime(timezone=True), server_default=db.func.now())
updated_at = db.Column(db.DateTime(timezone=True), onupdate=db.func.now())
You should assign sensor object to each entry in device list. My foolish way of achieving desirable result:
#classmethod
def get_device_sensor(cls):
device_sensor_schema = DeviceSensorSchema(many=True)
sensor_value_schema = SensorValueSchema(many=True)
device = Device.query.join(SensorData, Device.id == SensorData.device_id)\
.add_columns(Device.name.label('device_name'))
print(device)
sensor = Sensor.query.join(SensorData, Sensor.id == SensorData.sensor_id)\
.add_columns(Sensor.name.label('sensor_name'), SensorData.value.label('value'))
res_device[0].sensors = sensor
res_device = device_sensor_schema.dump(device, many=True)
if device:
return jsonify({'message': 'success', 'device': res_device})
else:
return {'message': 'Table device is empty'}, 404
In a better way to approach this you would make use of mapped SQLAlchemy object. In this case Device.sensors_data.

Django Rest framework post ForeignKey

I am using DRF to update data. Its works good, but I am struggling how to update foreign keys.
{
"name": "Ready Or Not",
"releases": [
{
"platform": {
"name": "test"
},
"date": "2019-10-02T11:38:18Z"
}
]
},
This is a response of my API.
But I want to update this 'releases' information as well.
To sent I have this. If the 'platform' name doesnt exist it should also create one. How do I do this?
headers = {
'Authorization': 'Token ' + ss_token,
}
data = {
"releases": [
{
"platform": {
"name": "wanttoupdate"
},
"date": "2019-10-02T11:38:18Z"
},
]
}
source = Source.objects.all().first()
url = source.url + str(947) + '/'
response = requests.patch(url, headers=headers, data=data)
My models:
class Game(models.Model):
name = models.CharField(max_length=255)
class Platform(models.Model):
name = models.CharField(max_length=255)
class Release(models.Model):
platform = models.ForeignKey(Platform, on_delete=models.CASCADE)
game = models.ForeignKey(Game, related_name='releases', on_delete=models.CASCADE)
date = models.DateTimeField()
To post a ForeignKey instance , you have to use its id, for example in you case
if request.method == 'POST':
platform = request.POST['platform'] # pass your html name parameter
release_obj = Release(platform_id = platform)
release_obj.save()

Retrieving data from JSON in python, and if object name matches, then store the key of that object

I am making REST calls on a server. The first REST call gets all the projects and from that I store the project's IDs in an array.
Below is the JSON.
For e.g. it would return something like this:
[
{
"expand": "description,lead,url,projectKeys",
"self": "http://localhost:8080/rest/api/2/project/10101",
"id": "10101",
"key": "GR1",
"name": "Group1Project",
"avatarUrls": {
"48x48": "http://localhost:8080/secure/projectavatar?avatarId=10324",
"24x24": "http://localhost:8080/secure/projectavatar?size=small&avatarId=10324",
"16x16": "http://localhost:8080/secure/projectavatar?size=xsmall&avatarId=10324",
"32x32": "http://localhost:8080/secure/projectavatar?size=medium&avatarId=10324"
},
"projectTypeKey": "software"
}
]
Then I'm looping through that array and making another REST call for each project id(10101).
This gives me groups/users against that project.
For example:
{
"self": "http://localhost:8080/rest/api/2/project/10000/role/10100",
"name": "Developers",
"id": 10100,
"actors": [
{
"id": 10207,
"displayName": "group2",
"type": "atlassian-group-role-actor",
"name": "group2",
"avatarUrl": "http://localhost:8080/secure/useravatar?size=xsmall&avatarId=10123"
}
]
}
I want to get all the project IDs where name == group2.
Following is my Python code for all of this but it's not working.
import requests
ids = []
response = requests.get('http://localhost:8080/rest/api/2/project',
auth=('*', '*'))
data = response.json()
for line in data:
ids.append(line["id"])
print(ids)
# Check if group exists in Project roles.
# If it does, then save the project name in the list of arrays.
projectNames = []
for id in ids:
url = 'http://localhost:8080/rest/api/2/project/'+id+'/role/10100'
response = requests.get(url,
auth = ('*', '*'))
data = response.json()
if data.displayName == 'group2':
projectNames.append(["id"])
Could you please help me out how to do this?
Thank you.
Tayyab,
You need to do this. It will work.
for actor in data['actors']:
if actor['displayName']=='group2':
projectNames.append(id)
projectNames = []
for id in ids:
url = 'http://localhost:8080/rest/api/2/project/'+id+'/role/10100'
response = requests.get(url,
auth = ('*', '*'))
data = response.json()
for actor in data["actors"]:
if actor["displayName"] and actor["displayName"] == "group2":
projectNames.append(actor["id"])
projectNames = set()
for id in ids:
url = 'http://localhost:8080/rest/api/2/project/'+id+'/role/10100'
response = requests.get(url,
auth = ('*', '*'))
data = response.json()
group2_actors = [actor['id'] for actor in data['actors']
if actor['displayName'] == 'group2']
if len(group2_actors) > 0:
projectNames.update(group2_actors)
projectNames is a set of unique actor ids with displayName == group2.
some_json = {}
result = [actor['id'] for actor in some_json['actors'] if actor['name']=='group2']
so result for that second json will be [10207]

auto field values in ndb.StructuredProperty

I want to store locations in google's datastore. Each entry shall have got 'sys'-fields, which shall contain information set by the datastore.
I've got the class model below and the WebService JSON request/response looks ok, but I have to set the values manually. It looks like auto_current_user_add, auto_now_add, auto_current_user and auto_now does not trigger.
from google.appengine.ext import ndb
from endpoints_proto_datastore.ndb import EndpointsModel
class Created(EndpointsModel):
by = ndb.UserProperty(auto_current_user_add=True)
on = ndb.DateTimeProperty(auto_now_add=True)
class Updated(EndpointsModel):
by = ndb.UserProperty(auto_current_user=True)
on = ndb.DateTimeProperty(auto_now=True)
class Sys(EndpointsModel):
created = ndb.StructuredProperty(Created)
updated = ndb.StructuredProperty(Updated)
class Location(EndpointsModel):
name = ndb.StringProperty(required=True)
description = ndb.TextProperty()
address = ndb.StringProperty()
sys = ndb.StructuredProperty(Sys)
When I submit a create request (location.put()) I get the following response:
{
"id": "4020001",
"name": "asdf"
}
When I set it manually using:
location.sys = Sys(created=Created(on=datetime.datetime.now(),
by=current_user),
updated=Updated(on=datetime.datetime.now(),
by=current_user))
location.put()
I get the expected result:
{
"id": "4020002",
"name": "asdf",
"sys": {
"created": {
"by": {
"auth_domain": "gmail.com",
"email": "decurgia#XYZ"
},
"on": "2015-01-27T16:05:41.465497"
},
"updated": {
"by": {
"auth_domain": "gmail.com",
"email": "decurgia#XYZ"
},
"on": "2015-01-27T16:05:41.465577"
}
}
}
How can I get those fields (sys.created.on, sys.created.by, sys.updated.on, sys.updated.by) automatically set?
In my limited work with StructuredProperty, I found it to be slower and more difficult to use than simply inserting the properties directly into the model. NDB seems to store those properties separately and perform a "join" when retrieving them. My recommendation is to use a "flat" model:
class Location(EndpointsModel):
name = ndb.StringProperty(required=True)
description = ndb.TextProperty()
address = ndb.StringProperty()
created_by = ndb.UserProperty(auto_current_user_add=True)
created_on = ndb.DateTimeProperty(auto_now_add=True)
updated_by = ndb.UserProperty(auto_current_user=True)
updated_on = ndb.DateTimeProperty(auto_now=True)
This should cause the auto_ properties to be triggered automatically.

Flask-SQLAlchemy and Flask-Restless not fetching grandchildren

Problem
I am building an app on Flask, Flask-SQLAlchemy, and Flask-Restless. I have used restless to generate an API for a parent-child-grandchild relationship*. A GET on my child will correctly fetch the grandchild, but a GET on the parent will not fetch the grandchild for each child.
*In fact, the parent-child relationship is a many-to-many, but same premise.
Models
class Grandchild(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False)
parent = db.relationship('Child', backref='grandchild')
parent_child = db.Table('parent_child',
db.Column('parent_id', db.Integer, db.ForeignKey('parent.id')),
db.Column('child_id', db.Integer, db.ForeignKey('child.id')),
db.Column('number', db.SmallInteger)
)
class Child(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False)
grandchild_id = db.Column(db.Integer, db.ForeignKey('grandchild.id'), nullable=False)
class Parent(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False)
children = db.relationship('Child', secondary=parent_child)
api.create_api(Child, exclude_columns=['grandchild_id'])
api.create_api(Parent)
GET: /api/child response
{
"num_results": 1,
"objects": [
{
"id": 1,
"name": "test"
"grandchild": {
"id": 1,
"name": "test"
}
}
],
"page": 1,
"total_pages": 1
}
GET: /api/parent response
{
"num_results": 1,
"objects": [
{
"children": [
{
"id": 1,
"name": "test",
"grandchild_id": 1
}
],
"id": 1,
"name": "test"
}],
"page": 1,
"total_pages": 1
}
postprocessors can be used to fetch grandchild.
def parent_post_get_many(result=None, search_params=None, **kw):
for object in result['objects']:
for child in object['children']:
grandchild = Grandchild.query.get(child['grand_child_id'])
child.update({'grandchild': grandchild})
api.create_api(Parent, postprocessors={'GET_MANY': [parent_post_get_many]})
After looking at this for a few hours I'm going to give the best answer I have at the moment. I've tried a number of approaches and haven't been able to get anything to successfully render the grandchild, so I turned to the flask-restless issues tracker to see what I could find:
https://github.com/jfinkels/flask-restless/pull/222#issuecomment-31326359 and #jfinkels response seem to indicate that what you want is currently not possible in flask-restless.
Assuming my assessment of the state of issues is correct, you may want to look into either designing around this issue, or using a different package to serve your API (perhaps Flask-restful, though I admit I haven't used it and don't know if it's suitable).
FWIW, I've been using Flask-Classy to build a json API for a project I'm working on. The process is a little more involved than I suspect you want, but it also comes with enough freedom to better control what queries are used and how the results are serialized.

Categories

Resources