My data is stored in elasticsearch and it is very big. So I want to use graphql to query it properly. I am using django graphene package to query it. For database models it is working fine. My json schema of elasticsearch
https://pastebin.com/EQBnnCBU
below is my Type definition and query code
https://pastebin.com/fsr9V1Rf
Problem is that I am not able to understand how to write the query schema for the elastic json schema.
need only initial help or any explanation that can help me
I have checked the answer here django-graphene without model But is of not help
My current ElasticType schema
class ElasticType(graphene.ObjectType):
id = graphene.ID()
index = graphene.String()
found = graphene.String()
properties = graphene.String()
You could give graphene-elastic a try.
As examples state, you will need to declare which fields do you want to filter on and it will automatically make them available for filtering using specified lookup filters.
Some code parts (not related to your project, but simply to indicate how it works, copied from the project documentation).
Sample document definition
import datetime
from elasticsearch_dsl import (
Boolean,
Date,
Document,
Keyword,
Nested,
Text,
Integer,
)
class Post(Document):
title = Text(
fields={'raw': Keyword()}
)
content = Text()
created_at = Date()
published = Boolean()
category = Text(
fields={'raw': Keyword()}
)
tags = Text(
analyzer='snowball',
fields={'raw': Keyword(multi=True)},
multi=True
)
num_views = Integer()
class Index:
name = 'blog_post'
settings = {
'number_of_shards': 1,
'number_of_replicas': 1,
'blocks': {'read_only_allow_delete': None},
}
def add_tag(self, name):
self.tags.append(name)
def save(self, ** kwargs):
self.created_at = datetime.datetime.now()
return super().save(** kwargs)
Sample schema definition
import graphene
from graphene_elastic import (
ElasticsearchObjectType,
ElasticsearchConnectionField,
)
from graphene_elastic.filter_backends import (
FilteringFilterBackend,
SearchFilterBackend,
)
from graphene_elastic.constants import (
LOOKUP_FILTER_PREFIX,
LOOKUP_FILTER_TERM,
LOOKUP_FILTER_TERMS,
LOOKUP_FILTER_WILDCARD,
LOOKUP_QUERY_EXCLUDE,
LOOKUP_QUERY_IN,
)
# Object type definition
class Post(ElasticsearchObjectType):
class Meta(object):
document = PostDocument
interfaces = (Node,)
filter_backends = [
FilteringFilterBackend,
SearchFilterBackend,
]
filter_fields = {
'title': {
'field': 'title.raw',
'lookups': [
LOOKUP_FILTER_TERM,
LOOKUP_FILTER_TERMS,
LOOKUP_FILTER_PREFIX,
LOOKUP_FILTER_WILDCARD,
LOOKUP_QUERY_IN,
LOOKUP_QUERY_EXCLUDE,
],
'default_lookup': LOOKUP_FILTER_TERM,
},
'category': 'category.raw',
'tags': 'tags.raw',
'num_views': 'num_views',
}
search_fields = {
'title': {'boost': 4},
'content': {'boost': 2},
'category': None,
}
# Query definition
class Query(graphene.ObjectType):
all_post_documents = ElasticsearchConnectionField(Post)
# Schema definition
schema = graphene.Schema(query=Query)
Sample queries
query PostsQuery {
allPostDocuments(filter:{
category:{terms:["Elastic", "Python"]}
}) {
edges {
node {
id
title
category
content
createdAt
comments
}
}
}
}
Or:
{
allPostDocuments(filter:{
category:{term:"Python"},
numViews:{gt:"700"}
}) {
edges {
node {
category
title
comments
numViews
}
}
}
}
Study documentation for more.
Related
Can't find a solution to this error please help or show me how to fix this.
The error is showing as follows:
(1048, "Column 'targetDefn_id' cannot be null") this error is showing when I post data.
This is my views.py in Post method I m getting this error:
def setTarget(request):
if request.method == 'POST':
data=JSONParser().parse(request)
print(data)
serial=TargetSerializers(data=data)
print(serial)
if serial.is_valid():
serial.save()
print("done")
return JsonResponse(serial.data,status=status.HTTP_200_OK,safe=False)
return JsonResponse(serial.errors, status=status.HTTP_400_BAD_REQUEST)
This is my Serializer.py as follows:
class TargetSerializers(serializers.ModelSerializer):
targetDefn=serializers.SerializerMethodField()
roleId=serializers.SerializerMethodField()
empId=serializers.SerializerMethodField()
class Meta:
model = Target
fields = (
'id',
'targetDefn',
'roleId',
'empId',
'startDate',
'endDate',
'value'
)
def get_targetDefn(self,obj):
trgt = TargetDefination.objects.get(id=obj.targetDefn_id)
serial = TargetDefinationSerializers(trgt)
return serial.data
def get_empId(self,obj):
emp= Employee.objects.get(id=obj.empId_id)
serial= OnlyEmployeeSerializers(emp)
return serial.data
def get_roleId(self,obj):
role=Role.objects.get(id=obj.roleId_id)
serial=RoleSerializers(role)
return serial.data
This is models.py as follows:
class Target(models.Model):
targetDefn=models.ForeignKey(TargetDefination,on_delete=models.CASCADE)
roleId=models.ForeignKey(Role,on_delete=models.CASCADE)
empId=models.ForeignKey(Employee,on_delete=models.CASCADE)
startDate= models.DateField(default=datetime.date.today)
endDate= models.DateField(null=True,blank=True)
value=models.PositiveIntegerField(default=0)
def __str__(self):
return str(self.empId) + ' ' +str(self.targetDefn)
Updated:
My Post query:
{
"targetDefn": {
"id": 1,
"targetName": "MIN SALES",
"displayName": "MIN SALES"
},
"roleId": {
"id": 3,
"roleName": "CIO",
"description": "chief information officer",
"roleReportsTo": 5,
"roleReportsToName": "SeniorVP(M)"
},
"empId": {
"id": 2,
"empName": "Emp02",
"startDate": "2021-04-01",
"termDate": null
},
"startDate": "2021-05-11",
"endDate": "2021-05-20",
"value": "123"
}
Know that the SerializerMethodField is READ-ONLY. It means that the data of those fields will not be written in the database. They will be computed and sent to your user, but never written in the DB. So, when you're saving your serializer, those fields are ignored.
I've noticed that you've created SerializerMethodField for all your foreign keys, only for their get_[field] method to return literally the serialized object. So why not simply use their nested-serializer right away?
class TargetSerializers(serializers.ModelSerializer):
targetDefn=TargetDefinationSerializers()
roleId=OnlyEmployeeSerializers()
empId=serializers.SerializerMethodField()
class Meta:
model = Target
fields = (
'id',
'targetDefn',
'roleId',
'empId',
'startDate',
'endDate',
'value'
)
If you cannot get it to work or wish to keep your SerializerMethodField structure, then we must add the data of those 3 fields before saving. You can either pass the data as parameter in the serializer, like so:
serializer.save(targetDefn=variable_1, roleId=variable_2, empId=variable_3)
Or you can override the create and update serializer methods to do it there, example:
def create(self, validated_data):
targetDefn = validated_data["targetDefn"]
roleId = validated_data["roleId"]
emp_id = validated_data["emp_id"]
# preprocess those data if needed
# Then create your model
Target.objects.create(targetDefn=targetDefn, ...)
Can i group results on the basic of field in User model.
models.py
class User(AbstractUser):
USERTYPE = (('1','type_1'),('2','type_2'),....)
user_type = models.CharField(max_length=2,choices=USERTYPE)
.....
views.py
User.object.all().values('first_name','last_name')
How can i get all users data with groupby there type in below format by using django ORM query only..
{
"type_1":[
{
"first_name":"abc",
"last_name":"xzy"
},
{
"first_name":"abcd",
"last_name":"wxzy"
}
],
"type_2":[
{
"first_name":"abcdd",
"last_name":"xzddy"
},
{
"first_name":"absdcd",
"last_name":"wxsdzy"
}
]
}
You can not do that in a query itself. But you can do some post-processing on the query:
from itertools import groupby
from operator import methodcaller
qs = User.object.order_by('user_type')
result = {
k: [{ 'first_name': u.first_name, 'last_name': u.last_name } for u in us]
for k, us in groupby(qs, methodcaller('get_user_type_display'))
}
We here thus order the queryset by the user_type field, and then let groupby(..) make groups based on the get_user_type_display() method. Then we can make sublists for each such group.
My API endpoint is http://127.0.0.1:7009/apps/2/versions
I am unable to filter, order and search the particular version data
models.py:
class App(models.Model):
app_id = models.CharField(max_length=40,help_text="app_id of the app",unique=True)
name=models.CharField(max_length=40,help_text="name of the app")
class AppVersion(models.Model):
app_version = models.CharField(max_length=200)
app_description = models.CharField(max_length=200,blank=True)
Views.py :
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import OrderingFilter,SearchFilter
class AppVersionListView(mixins.ListModelMixin,mixins.CreateModelMixin,generics.GenericAPIView):
lookup_field = 'pk'
serializer_class = appVersionsSerializer
queryset = AppVersion.objects.all()
filter_backends = (DjangoFilterBackend, OrderingFilter,SearchFilter,)
filter_fields = ('id','app_version','app_description ')
ordering_fields = '__all__'
search_fields =('app_version','app_description')
serializers.py : (class for app_versions)
class appVersionsSerializer(QueryFieldsMixin,serializers.ModelSerializer):
class Meta:
model = AppVersion
fields = ('apps','app_version','app_description')
I want to filter the versions data based on "app_description" i.e.,
GET:
http://127.0.0.1:7009/apps/2/versions?app_description =FileCommander
Expected Output :
Should filter the data and return results which is having that description
[
{
"apps": 2,
"app_version": "v1",
"app_description ":"FileCommander"
}]
Actual Output :
[
{
"apps": 2,
"app_version": "v1",
"app_description ":"FileCommander"
},
{
"apps": 2,
"app_version": "v2",
"app_description ":"cooking"
}]
How can I search , filter or order the versions data?
When I execute a mutation (with SerializerMutation) and return the created object, the response contains an AssertionError that states
User Error: expected iterable, but did not find one for field CreateTableMutationPayload.footSet
The issue is in executor.py complete_list_value that checks that the footSet is an iterable. It is in fact a RelatedManager, which is not iterable as is. Normally, you'd just do a table.foot_set.all() to get the iterable. I find it stange that it is working fine in Queries but not Mutations.
I created a sample project to illustrate this.
I have a pretty simple model of Table with several Foot. Both objects are exposed with Relay and this works great. Querying:
{ tables {
edges {
node {
id, name, height
footSet {
edges {
node {
id, number, style
} } } } } } } }
returns:
{
"data": {
"tables": {
"edges": [
{
"node": {
"id": "VGFibGVOb2RlOjE=",
"name": "test1",
"height": 11,
"footSet": {
"edges": [
{
"node": {
"id": "Rm9vdE5vZGU6MQ==",
"number": 1,
"style": "plain"
}
},
{
"node": {
"id": "Rm9vdE5vZGU6Mg==",
"number": 2,
"style": "Almost plain"
} } ] } } } ] } } }
But a mutation:
mutation {
createTable(input: {
name:"test3"
height: 60
footSet: [
{ number: 1, style: "Rococo" }
]
}) {
name
height
footSet {
id
number
style
}
}
}
Yields:
{
"errors": [
{
"message": "User Error: expected iterable, but did not find one for field CreateTableMutationPayload.footSet. (furniture.Foot.None)"
}
],
"data": {
"createTable": {
"name": "test3",
"height": 60,
"footSet": null
}
}
}
To use the sample, you should just need to
source bin/activate
pip -r requirements.txt
./manage.py migrate
./manage.py createsuperuser
./manage.py runserver :7000
Connect to localhost:7000/admin
Go to localhost:7000/graphql
The schema.py:
import json
import graphene
from graphene import Schema
from graphene_django import DjangoObjectType
from graphene_django.filter import DjangoFilterConnectionField
from furniture.models import Table, Foot
from graphene_django.rest_framework.mutation import SerializerMutation
from furniture.serializers import TableSerializer
class TableNode(DjangoObjectType):
class Meta:
model = Table
filter_fields = "__all__"
interfaces = (graphene.relay.Node,)
class FootNode(DjangoObjectType):
class Meta:
model = Foot
filter_fields = "__all__"
interfaces = (graphene.relay.Node,)
class Query(graphene.ObjectType):
tables = DjangoFilterConnectionField(TableNode)
class CreateTableMutation(SerializerMutation):
class Meta:
serializer_class = TableSerializer
model_operations = ['create', 'update']
lookup_field = 'id'
class Mutation(graphene.ObjectType):
create_table = CreateTableMutation.Field()
schema = Schema(query=Query, mutation=Mutation)
and serializers.py:
from rest_framework import serializers
from .models import Table, Foot
class FootSerializer(serializers.Serializer):
class Meta:
model = Foot
number = serializers.IntegerField()
style = serializers.CharField()
def update(self, instance, validated_data):
pass
def create(self, validated_data):
pass
def get_attribute(self, instance):
print("get_attr", self, instance)
return []
class TableSerializer(serializers.Serializer):
class Meta:
model = Table
name = serializers.CharField()
height = serializers.IntegerField()
foot_set = FootSerializer(many=True, required=False)
def update(self, instance, validated_data):
pass
def create(self, validated_data):
feet = validated_data.pop('foot_set') if 'foot_set' in validated_data else []
print("feet", type(feet), str(feet))
table = Table.objects.create(name=validated_data['name'], height=validated_data['height'])
for foot in feet:
Foot.objects.create(table=table, number=foot['number'], style=foot['style'])
table.refresh_from_db()
print("created table", table)
return table
# also tried Table.objects.filter(id=table.id).prefetch_related("foot_set").first()
How can I return my model with its potential subobject for Graphene to process according to the requirements on the mutation ? Am I doing it all wrong ? Does someone have such an example that works ?
I need to group the result of a queryset by date on DRF
""" Django model """
class Matches(models.Model):
name = models.CharField(max_length=100)
platform = models.CharField(max_length=100)
mode = models.CharField(max_length=100)
kills = models.IntegerField()
date = models.DateTimeField()
""" Serializer """
class MatchesSerializer(serializers.ModelSerializer):
class Meta:
model = models.Matches
fields = ('name', 'platform', 'mode', 'kills', 'date')
""" views """
class Matches(generics.ListAPIView):
serializer_class = serializers.MatchesSerializer
filter_backends = (filters.OrderingFilter,)
lookup_field = 'name'
ordering = ('-date',)
def get_queryset(self):
username = self.kwargs['name']
return models.Matches.objects.filter(name=username)
Desired output (just an example):
[
{
'date':'2019-01-01',
'data':[
{
'platform':'ps4',
'mode':'solo',
'kills':10,
'date':'2019-01-01 10:00:00'
},
{
'platform':'ps4',
'mode':'duo',
'kills':10,
'date':'2019-01-01 12:00:00'
},
{
'platform':'ps4',
'mode':'squad',
'kills':10,
'date':'2019-01-01 11:00:00'
},
]
},
{
'date':'2019-01-02',
'data':[
{
'platform':'ps4',
'mode':'solo',
'kills':1,
'date':'2019-01-02 10:00:00'
},
{
'platform':'ps4',
'mode':'duo',
'kills':2,
'date':'2019-01-02 12:00:00'
},
{
'platform':'ps4',
'mode':'squad',
'kills':3,
'date':'2019-01-02 11:00:00'
},
]
}
]
For me, the easy solution is to make a raw querie on django and create a serializer, but it feels not so pythonic...
So it appears that DRF has some beautiful way to make it look nice, maybe using to_representation...
I used the itertools.groupby iterator. Check my code below.
from itertools import groupby
events = [["2020-04-01", "A"], ["2020-04-01", "B"], ["2020-04-02", "C"], ["2020-04-02", "D"]]
for k, g in groupby(events, lambda x: x[0]):
list = []
for group in g:
list.append(group[1])
output[k] = list
The output will be grouped by date as follows
{'2020-04-01': ['A', 'B'], '2020-04-02': ['C', 'D']}
Please make sure your order by date first.
You can use the function raw from Django ORM
results = Matches.objects.raw('SELECT * FROM myapp_matches GROUP BY date')