`op_name` parameter for `graphene_django` - django

The django graphene documentation shows a test example like this:
class MyFancyTestCase(GraphQLTestCase):
def test_some_query(self):
response = self.query(
'''
query {
myModel {
id
name
}
}
''',
op_name='myModel'
)
content = json.loads(response.content)
# This validates the status code and if you get errors
self.assertResponseNoErrors(response)
# Add some more asserts if you like
...
They don't have any API documentation for what op_name is, and what we should set it as. I tried to set it to my query name, but get the error:
[{'message': 'Unknown operation named "myQuery".'}]

Operation name is only needed when there are multiple operations in the query string. You only have one operation so the default (None) is fine.
https://docs.graphene-python.org/en/latest/execution/execute/#operation-name

As per my comment:
If the query is a mutation or named query, you must supply the op_name. For annon queries ("{ ... }"), should be None (default)
I am not sure how to create a "named query" with django graphene, but apparently my query is NOT a named query. Leaving op_name as None got my query to work via my unit test.

Related

Related posts by tag name

i want to show related posts by tag name However i got the error " get() returned more than one Tag -- it returned 2!"
def post_detail(request,slug):
post=get_object_or_404(Post,slug=slug)
comments=Comment.objects.filter(post=post,reply=None,statusc=2).order_by('-date')
comment_count=len(Comment.objects.filter(post=post, statusc=2))
tag=get_object_or_404(Tag,post=post)
related_item=Post.objects.filter(tag__tag_name__icontains=tag.tag_name,status=2).order_by('-created_date').distinct()[:3]
You can just query like:
def post_detail(request,slug):
post=get_object_or_404(Post,slug=slug)
comments=Comment.objects.filter(post=post,reply=None,statusc=2).order_by('-date')
comment_count=len(comments)
related_items = Post.objects.filter(
tag__post=post
).order_by('-created_date').distinct()[:3]
# ...
Or if you want to exclude the current post:
def post_detail(request,slug):
post=get_object_or_404(Post,slug=slug)
comments=Comment.objects.filter(post=post,reply=None,statusc=2).order_by('-date')
comment_count=len(comments)
related_items = Post.objects.exclude(pk=post.pk).filter(
tag__post=pos
).order_by('-created_date').distinct()[:3]
# ...
It is also better to perform a len(..) on the comments, since that will result in making a query to fetch the comments, whereas using two separate queries, will hit the database twice.
As per documentation, get() is used for retrieving 1 item. If there are multiple items, here there could be multiple tags used in single Post, it will throw error.
So, you can change it like this:
tags=Tag.objects.filter(post=post)
related_item=Post.objects.filter(tag__in=tags,status=2).order_by('-created_date').distinct()[:3]

DJANGO API REST FRAMEWORK: schema methods

Django 1.11.3, python 3.6
I have 2 classes in my view.py:
class ProductList(generics.ListAPIView):
class SampleList(generics.ListAPIView):
Please note the same superclass. Might be relevant: Product is an actual model, Sample is not, SampleList is just a method that calls Product.objects.all() (same code as in ProductList)
All the code inside those classes besides class names is IDENTICAL (including serializer) - I just copied the class and renamed the copy).
The client before it hits urls for those two gets the schema
schema = self.client.get(self.myAppApiUrl)
#works, returns the results
result1 = self.client.action(schema, ["products", "list"])
params = {"id" : some_id, }
#fails with this: coreapi.exceptions.LinkLookupError: Index ['samples']['list'] did not reference a link. Key 'list' was not found.
result2 = self.client.action(schema, ["samples", "list"], params)
When I print "schema", I see
products: {
list([page])
}
samples: {
read(id)
}
My questions are: what makes it to add "list" to schema in the first case and "read" in the second case? And how can I add "list" to the second case? Maybe some schema update needs to be done somehow? The API web server was restarted.
What does that message "Key 'list' was not found" mean? Does this failure have something to do with the params passed? Removing params from the client call does not change anything.
I am also somewhat curious about what is that "page" thing in list and what adds that and but that's not important.

Validate custom field with Flask-RESTPlus

I'm trying to create a custom field for validating POSTed JSON in my API using Flask-RESTPlus 0.10.1
Below is the basic setup...
from flask_restplus import fields
import re
EMAIL_REGEX = re.compile(r'\S+#\S+\.\S+')
class Email(fields.String):
__schema_type__ = 'string'
__schema_format__ = 'email'
__schema_example__ = 'email#domain.com'
def validate(self, value):
if not value:
return False if self.required else True
if not EMAIL_REGEX.match(value):
return False
return True
I like the way the above documents in Swagger UI, but I can't seem to figure out how to actually use the validate method on it.
Here's how I'm using the custom field.
Json = api.model('Input JSON', {
'subscribers': fields.List(Email),
[...]
})
#api.expect(Json) // validate is globally set to true
def post(self):
pass
I've had luck using
'subscribers': fields.List(fields.String(pattern='\S+#\S+\.\S+')) instead, but this doesn't give me the control to customize the error message, where'd I'd like it to return that the field is not of the email type.
I've also gone on and added a custom validate_payload function (found within http://aviaryan.in/blog/gsoc/restplus-validation-custom-fields.html) that I call again within my POST method (instead of api.expect). This requires me to duplicate some core functionality and call it every time in addition to api.expect to output the proper Swagger documentation and a little bit of finesse to get it to work within nested fields.
It's my understanding that this should work out of box? Am I wrong? What am I missing here?
I appreciate this is a little old but just had the same issue.
It looks like the "validate" actually sat over a python jsonschema impl, if you're still interested in digging, it's available here
That aside - you can configure restplus API to use a better formatchecker as follows: (I also validate date-time and date)
format_checker = FormatChecker(formats=["date-time", "email", "date"])
api_v1 = Api(
app, version='1.4',
title='[Anon]',
description='[Anon] API for developers',
format_checker=format_checker
)

Django get_or_create with icontains

I'm getting an unexpected result using icontains in my get_or_create call.
Take the following example:
>>>team_name = "Bears"
>>>Team.objects.get(name__icontains=team_name) # returns DoesNotExist as expected
>>>team, created = Team.objects.get_or_create(name__icontains=team_name)
>>>print(created) # Prints True as expected
>>>print(team.name) # Prints an empty string!
Why does this create a team with a blank name rather than "Bears"? The reason I'm using get_or_create here is that if a subsequent user posts something like "BearS" I want to get the correct team, not create a duplicate team with incorrect capitalization.
I think here you should split the get() and create() functionalities instead of using get_or_create(), because the __icontains lookup works for get() only.
Try doing something like this:
>>> team_name = 'Bears'
>>> teams = Team.objects.filter(name__icontains=team_name)
# This will filter the teams with this name
>>> team = teams.first() if teams.exists() else Team.objects.create(name=team_name)
# Now your team is the first element of your previous query (it returns a QuerySet with single element) if it exists
# Otherwise, you create a new Team.
Another option besides wencakisa's answer is to include the defaults parameter in get_or_create, because Django strips lookups containing the __ separator. See answers to this question.
The code would be:
Team.objects.get_or_create(
name__icontains=team_name,
defaults = {
"name": team_name
}
)
The right way to do it is using Django's function get_or_create(). But instead of "icontains", you should use "iexact" (), unless you want an exact match, in wich case you should use just "exact":
Team.objects.get_or_create(
name__iexact=team_name,
defaults = {
"name": team_name
}
)
Outside "defaults" you should put your search terms. If the objects doesn't exist, you should write your creation terms inside 'defaults'

Pulling data from datastore and converting it in Json in python(Google Appengine)

I am creating an apllication using google appengine, in which i am fetching a data from the website and storing it in my Database (Data store).Now whenever user hits my application url as "application_url\name =xyz&city= abc",i am fetching the data from the DB and want to show it as json.Right now i am using a filter to fetch data based on the name and city but getting output as [].I dont know how to get data from this.My code looks like this:
class MainHandler(webapp2.RequestHandler):
def get(self):
commodityname = self.request.get('veg',"Not supplied")
market = self.request.get('market',"No market found with this name")
self.response.write(commodityname)
self.response.write(market)
query = commoditydata.all()
logging.info(commodityname)
query.filter('commodity = ', commodityname)
result = query.fetch(limit = 1)
logging.info(result)
and the db structure for "commoditydata" table is
class commoditydata(db.Model):
commodity= db.StringProperty()
market= db.StringProperty()
arrival= db.StringProperty()
variety= db.StringProperty()
minprice= db.StringProperty()
maxprice= db.StringProperty()
modalprice= db.StringProperty()
reporteddate= db.DateTimeProperty(auto_now_add = True)
Can anyone tell me how to get data from the db using name and market and covert it in Json.First getting data from db is the more priority.Any suggestions will be of great use.
If you are starting with a new app, I would suggest to use the NDB API rather than the old DB API. Your code would look almost the same though.
As far as I can tell from your code sample, the query should give you results as far as the HTTP query parameters from the request would match entity objects in the datastore.
I can think of some possible reasons for the empty result:
you only think the output is empty, because you use write() too early; app-engine doesn't support streaming of response, you must write everything in one go and you should do this after you queried the datastore
the properties you are filtering are not indexed (yet) in the datastore, at least not for the entities you were looking for
the filters are just not matching anything (check the log for the values you got from the request)
your query uses a namespace different from where the data was stored in (but this is unlikely if you haven't explicitly set namespaces anywhere)
In the Cloud Developer Console you can query your datastore and even apply filters, so you can see the results with-out writing actual code.
Go to https://console.developers.google.com
On the left side, select Storage > Cloud Datastore > Query
Select the namespace (default should be fine)
Select the kind "commoditydata"
Add filters with example values you expect from the request and see how many results you get
Also look into Monitoring > Log which together with your logging.info() calls is really helpful to better understand what is going on during a request.
The conversion to JSON is rather easy, once you got your data. In your request handler, create an empty list of dictionaries. For each object you get from the query result: set the properties you want to send, define a key in the dict and set the value to the value you got from the datastore. At the end dump the dictionary as JSON string.
class MainHandler(webapp2.RequestHandler):
def get(self):
commodityname = self.request.get('veg')
market = self.request.get('market')
if commodityname is None and market is None:
# the request will be complete after this:
self.response.out.write("Please supply filters!")
# everything ok, try query:
query = commoditydata.all()
logging.info(commodityname)
query.filter('commodity = ', commodityname)
result = query.fetch(limit = 1)
logging.info(result)
# now build the JSON payload for the response
dicts = []
for match in result:
dicts.append({'market': match.market, 'reporteddate': match.reporteddate})
# set the appropriate header of the response:
self.response.headers['Content-Type'] = 'application/json; charset=utf-8'
# convert everything into a JSON string
import json
jsonString = json.dumps(dicts)
self.response.out.write( jsonString )