Graphene-django - How to catch response of query? - python

I use django and django graphene for make a graphql API.
In the view of my application, I use reactJS and react-bootstrap-table. React-bootstrap-table expects that I pass it an object array but does not support nested objects.
I created query in my schema.py:
class ApplicationNode(DjangoObjectType):
class Meta:
model = Application
filter_fields = ['name', 'sonarQube_URL']
interfaces = (relay.Node,)
class Query(ObjectType):
application = relay.Node.Field(ApplicationNode)
all_applications = DjangoFilterConnectionField(ApplicationNode)
The answers to these queries are JSON nested objects like this:
{
"data": {
"allApplications": {
"edges": [
{
"node": {
"id": "QXBwbGljYXRpb25Ob2RlOjE=",
"name": "foo",
"sonarQubeUrl": "foo.com",
"flow":{
"id": "QYBwbGljYXRpb45Ob2RlOjE=",
"name": "flow_foo"
}
}
},
{
"node": {
"id": "QXBwbGljYXRpb25Ob2RlOjI=",
"name": "bar",
"sonarQubeUrl": "bar.com"
"flow":{
"id": "QXBwbGljYXRpb26Ob2RlOjA=",
"name": "flow_bar"
}
}
}
]
}
}
}
I have to put them flat before giving them to React-bootstrap-table.
What is the better way, intercept the results of graphene-django queries to put them flat or make this job in ReactJS view?
If the first way is better, how to intercept the results of graphene-django queries to put them flat?

The best thing to do is to wrap react-bootstrap-table in a new component. In the component massage the relay props into a flat structure as needed for react bootstrap table.
For example:
MyReactTable = ({allApplications}) => {
let flatApplications = allApplications.edges.map(({node: app}) => {
return {
name: app.name,
sonarQubeUrl: app.sonarQubeUrl,
flowName: app.flow.name
};
});
return (
<BootstrapTable data={flatApplications} striped={true} hover={true}>
<TableHeaderColumn dataField="name" isKey={true} dataAlign="center" dataSort={true}>Name</TableHeaderColumn>
<TableHeaderColumn dataField="sonarQubeUrl" dataSort={true}>Sonar Qube Url</TableHeaderColumn>
<TableHeaderColumn dataField="flowName" dataFormat={priceFormatter}>Flow Name</TableHeaderColumn>
</BootstrapTable>
);
};

Related

SQLAlchemyObjectType.Meta two models graphene

I am trying to combine two SQLAlchemyConnectionField. The current error i face is graphql.error.base.GraphQLError: Expected value of type "PostsObject" but got: Tag
My current connections are defined like so posts = SQLAlchemyConnectionField(PostsObject.connection, /* input arguments like posts(name: "") */) Is there a way to add another type or allow to return something like
"data": {
"posts": {
"edges": [
{
"node": "Different table"
},
{
"node": "Other table"
}]}},
I am using graphene_sqlalchemy well anyway thats all thanks !

PynamoDB dynamic names for MapAttribute

I'm currently a bit stuck. I have to create a model of our dynamodb using pynamodb, and here's what I have (part of a bigger model, exported from a real user in DB)
packs = [
{
"exos": {
"4": {
"start": 1529411739,
"session": 1529411739,
"finish": 1529417144
},
"5": {
"start": 1529417192,
"session": 1529417192
}
},
"id": 10
},
{
"exos": {
"32": {
"start": 1529411706,
"session": 1529411706
}
},
"id": 17
}
]
Here's what I got so far:
class ExercisesMapAttribute(MapAttribute):
pass
class PackMapAttribute(MapAttribute):
exos = ExercisesMapAttribute()
id = NumberAttribute()
class TrainUser(Model):
class Meta:
table_name = 'TrainUser'
region = 'eu-west-1'
# [...] Other stuff removed for clarity
packs = ListAttribute(of=PackMapAttribute())
Currently I think I got correctly up until the "4":, "5": etc... As they are exercices name.
The idea is that this structure is supposed to represent a list of packs, then inside a list of exercises with their id and more info... I need a way to map that from the current db json to classes I can then use with PynamoDB. Is it even possible?
Thanks!
I've tried DynamicMapAttribute but I can't figure out if it will work with my configuration.
I also don't know how a custom attribute could be done to overcome this.

Saving a JSON list - Django

I am working with a JSON request.get that returns a list. I will like to save each individual object in the response to my models so I did this:
in views.py:
def save_ram_api(request):
r = requests.get('https://ramb.com/ciss-api/v1/')
# data = json.loads(r)
data = r.json()
for x in data:
title = x["title"]
ramyo_donotuse = x["ramyo"]
date = x["date"]
thumbnail = x["thumbnail"]
home_team_name = x["side1"]["name"]
away_team_name = x["side2"]["name"]
competition_name = x["tournament"]["name"]
ramAdd = ramSample.objects.create(title=title, ramyo_donotuse=ramyo_donotuse, date=date, thumbnail=thumbnail, home_team_name=home_team_name, away_team_name=away_team_name, competition_name=competition_name)
ramAdd.save()
return HttpResponse("Successfully submitted!")
This works fine except that it would only save the last objects on the list.
the JSON response list (as a random 60 objects at any time) would look something like:
[
{
"title": "AY - BasketMouth",
"ramyo": "AY de comedian"
"side1": {
"name": "Comedy Central",
"url": "https:\/\/www.rabithole.com\/laugh\/dave-chappel\/"
},
"side2": {
"name": "Basket Mouth",
"url": "https:\/\/www.rabithole.com\/laugh\/chris-rockie\/"
},
"tournament": {
"name": "Night of a thousand laugh",
"id": 15,
"url": "https:\/\/www.rabithole.com\/laugh\/chris-rockie\/"
},
"points": [
{
"nature": "Gentle",
"phrase": "Just stay"
},
{
"nature": "Sarcastic",
"phrase": "Help me"
}
]
},
{
"title": "Dave - Chris",
"ramyo": "Dave Chapelle"
"side1": {
"name": "Comedy Central",
"url": "https:\/\/www.rabithole.com\/laugh\/dave-chappel\/"
},
"side2": {
"name": "Chris Rockie",
"url": "https:\/\/www.rabithole.com\/laugh\/chris-rockie\/"
},
"tournament": {
"name": "Tickle me",
"id": 15,
"url": "https:\/\/www.rabithole.com\/laugh\/chris-rockie\/"
},
"points": [
{
"nature": "Rogue",
"phrase": "Just stay"
}
]
}
]
In this case my views.py will only save the last dictionary on the list, ignoring the other 59.
My question would be:
How do I get the views.py to save the entire objects on the list?
Notice that the "points" is also a list that contains one or more dictionaries, any help how to save this as well?
Your code is saving only the last object in the list because you are creating and saving the object outside of the loop. Try this,
def save_ram_api(request):
r = requests.get('https://ramb.com/ciss-api/v1/')
# data = json.loads(r)
data = r.json()
for x in data:
title = x["title"]
ramyo_donotuse = x["ramyo"]
date = x["date"]
thumbnail = x["thumbnail"]
home_team_name = x["side1"]["name"]
away_team_name = x["side2"]["name"]
competition_name = x["tournament"]["name"]
ramAdd = ramSample.objects.create(title=title, ramyo_donotuse=ramyo_donotuse, date=date, thumbnail=thumbnail, home_team_name=home_team_name, away_team_name=away_team_name, competition_name=competition_name)
ramAdd.save()
return HttpResponse("Successfully submitted!")
How do I get the views.py to save the entire objects on the list?
Notice that the "points" is also a list that contains one or more
dictionaries, any help how to save this as well?
Regarding your those questions
If you are using PostgreSQL as a database then you can use Django's built is JSONField and ArrayField for PostgreSQL database.
And if your database is not PostgreSQL you can use jsonfield library.

Eve: how to use different endpoints to access the same collection with different filters

I have an Eve app publishing a simple read-only (GET) interface. It is interfacing a MongoDB collection called centroids, which has documents like:
[
{
"name":"kachina chasmata",
"location":{
"type":"Point",
"coordinates":[-116.65,-32.6]
},
"body":"ariel"
},
{
"name":"hokusai",
"location":{
"type":"Point",
"coordinates":[16.65,57.84]
},
"body":"mercury"
},
{
"name":"caƱas",
"location":{
"type":"Point",
"coordinates":[89.86,-31.188]
},
"body":"mars"
},
{
"name":"anseris cavus",
"location":{
"type":"Point",
"coordinates":[95.5,-29.708]
},
"body":"mars"
}
]
Currently, (Eve) settings declare a DOMAIN as follows:
crater = {
'hateoas': False,
'item_title': 'crater centroid',
'url': 'centroid/<regex("[\w]+"):body>/<regex("[\w ]+"):name>',
'datasource': {
'projection': {'name': 1, 'body': 1, 'location.coordinates': 1}
}
}
DOMAIN = {
'centroids': crater,
}
Which will successfully answer to requests of the form http://hostname/centroid/<body>/<name>. Inside MongoDB this represents a query like: db.centroids.find({body:<body>, name:<name>}).
What I would like to do also is to offer an endpoint for all the documents of a given body. I.e., a request to http://hostname/centroids/<body> would answer the list of all documents with body==<body>: db.centroids.find({body:<body>}).
How do I do that?
I gave a shot by including a list of rules to the DOMAIN key centroids (the name of the database collection) like below,
crater = {
...
}
body = {
'item_title': 'body craters',
'url': 'centroids/<regex("[\w]+"):body>'
}
DOMAIN = {
'centroids': [crater, body],
}
but didn't work...
AttributeError: 'list' object has no attribute 'setdefault'
Got it!
I was assuming the keys in the DOMAIN structure was directly related to the collection Eve was querying. That is true for the default settings, but it can be adjusted inside the resources datasource.
I figured that out while handling an analogous situation as that of the question: I wanted to have an endpoint hostname/bodies listing all the (unique) values for body in the centroids collection. To that, I needed to set an aggregation to it.
The following settings give me exactly that ;)
centroids = {
'item_title': 'centroid',
'url': 'centroid/<regex("[\w]+"):body>/<regex("[\w ]+"):name>',
'datasource': {
'source': 'centroids',
'projection': {'name': 1, 'body': 1, 'location.coordinates': 1}
}
}
bodies = {
'datasource': {
'source': 'centroids',
'aggregation': {
'pipeline': [
{"$group": {"_id": "$body"}},
]
},
}
}
DOMAIN = {
'centroids': centroids,
'bodies': bodies
}
The endpoint, for example, http://127.0.0.1:5000/centroid/mercury/hokusai give me the name, body, and coordinates of mercury/hokusai.
And the endpoint http://127.0.0.1:5000/bodies, the list of unique values for body in centroids.
Beautiful. Thumbs up to Eve!

Django rest - convert field into a list?

I have a Textfield in my model which stores dictionaries, I would like to convert this field into a dictionary if possible in a rest serializer.
at the moment the field returns the dictionary but backslashes all the quotes, it is possible to convert the strings into a nested list of dicts?
Thanks
api currently returns below:
{
"id": 3,
"hostname": "WAN-EDGE",
"timestamp": "2019-04-12T11:34:36.654521",
"routing_table": "[{\"route\": \"0.0.0.0\", \"subnet_mask\": \"0.0.0.0\", \"next_hop\": \"172.16.66.193\"}, {\"route\": \"10.10.21.0\", \"subnet_mask\": \"255.255.255.0\", \"next_hop\": \"172.16.67.146\"}, {\"route\": \"10.22.0.0\", \"subnet_mask\": \"255.255.0.0\", \"next_hop\": \"172.18.1.5\"}, {\"route\": \"10.31.0.0\", \"subnet_mask\": \"255.255.0.0\", \"next_hop\": \"172.16.67.146\"},...]"
},...
}
desired result a nested list of dicts
{
"id": 3,
"hostname": "WAN-EDGE",
"timestamp": "2019-04-12T11:34:36.654521",
"routing_table": [
{
"route": "0.0.0.0",
"subnet_mask": "0.0.0.0",
"next_hop": "172.16.66.193"
},
{
"route": "10.10.21.0",
"subnet_mask": "255.255.255.0",
"next_hop": "172.16.67.146"
},
{
"route": "10.22.0.0",
"subnet_mask": "255.255.0.0",
"next_hop": "172.18.1.5"
},
{
"route": "10.31.0.0",
"subnet_mask": "255.255.0.0",
"next_hop": "172.16.67.146"
},...
]
},...
}
Current serialiser:
class RoutingTableSerializer(serializers.ModelSerializer):
hostname = serializers.ReadOnlyField(
source='device.hostname',
)
rt = serializers.JSONField(
source='routing_table'
)
class Meta:
model = DeviceData
fields = ('id','hostname','timestamp','rt')
You may need serializers.JSONField()
Update-1
You could also try with SerializerMethodField() as
import json
class RoutingTableSerializer(serializers.ModelSerializer):
hostname = serializers.ReadOnlyField(source='device.hostname', )
rt = serializers.SerializerMethodField(source='routing_table', read_only=True)
def get_routing_table(self, instance):
return json.loads(instance.routing_table)
class Meta:
model = DeviceData
fields = ('id', 'hostname', 'timestamp', 'rt')

Categories