Graphene: How to add a function before query execute? - annotations

Is there a way to execute a function before all query?
When I add an annotation above Query class, It makes an error
AssertionError: Type <function Query at 0x104d1dd30> is not a valid ObjectType.
def my_func(f):
#wraps(f)
def my_func_wrap(*args, **kwargs):
//do something
return f(*args, **kwargs)
return my_func_wrap
#my_func
class Query(graphene.ObjectType):
node = relay.Node.Field()
users = graphene.List(lambda: UserSchema)
def resolve_users(self, info):
//do something
return User.query.all()
schema = graphene.Schema(query=Query)
If i add the annotation to every resolver, It works fine.
but I will add more than 20 resolvers and I don't think adding the annotation to every resolver is good idea.

Yes, you can. Just create a custom View class inheriting from GraphQLView and override dispatch method then use your own view class as graphql endpoint handler. Something like this:
class CustomGraphQLView(GraphQLView):
def dispatch(self, request, *args, **kwargs):
// do something
super(CustomGraphqlView, self).dispatch(request, *args, **kwargs)
If you want to manipulate the queryset itself, I suggest to use graphene-django-extras and override the list_resolver method on its query fields(DjangoFilterListField, DjangoFilterPaginateListField, ...) class and use your own custom class.
You can call super on override methods or copy the exact code from their source and edit them.

Related

How to call save method in mongoengine.EmbeddedDocument class

import mongoengine
class Model1(mongoengine.DynamicDocument):
name = mongoengine.StringField()
addr = mongoengine.EmbeddedDocumentField(Model2)
class Model2(mongoengine.EmbeddedDocument):
loc = mongoengine.StringField()
# do some stuff
def save(self, *args, **kwargs):
print "test line print...."
super(Model2, self).save(*args, **kwargs)
now when I save Model1 instance. it doesn't call save method
m2 = Model2(loc='some text')
m1 = Model1(name='name')
m1.addr = m2
m1.save()
if I try to explicity call the save method on Model2, it complains that NoneType object has no attr save
m2 (embedded doc) does have a save method. It calls m1.save(). See the code.
The assumption calling m1.save() will call save() on all embedded documents is false. (I fell in the same trap...)
So unfortunately, you can't safely override an embedded document's save method expecting it to be called each time the document is saved.
But you can add it a pre_save method you call from m1.save() (or in a callback catching the pre_save signal in the document).
However, calling m2.save() should call m1.save() and save the whole document. I can't explain this error: NoneType object has no attr save. You should edit your question to provide the full traceback.

flask redirect from closure

def check_login(func):
"""Check if user is logged in."""
def decorator(*args, **kwargs):
if not login_session_test():
print ("Not logged in - redirect to /login")
flash ("Well that was wrong. Chicken winner. No more dinner.")
return redirect(url_for('login'))
print ("Logged in, do what needs to be done.")
return func(*args, **kwargs)
return decorator
#check_login
#app.route("/sacred/secret/stuff", methods=['GET'])
def funfunfun():
return "Super fun"
It never redirects to /login but gives some garbage like page.
Swapping the #/closure order yields:
AssertionError: View function mapping is overwriting an existing endpoint function: decorator
I am not yet fully pythonized.
Your decorator order is incorrect, and you are not copying across the function name to the wrapper function.
Use this order:
#app.route("/sacred/secret/stuff", methods=['GET'])
#check_login
def funfunfun():
return "Super fun"
Otherwise the undecorated function is registered for the view.
Use #functools.wraps() to have various pieces of metadata copied over from the original wrapped function to the wrapper that replaces it:
from functools import wraps
def check_login(func):
"""Check if user is logged in."""
#wraps(func)
def decorator(*args, **kwargs):
if not login_session_test():
print ("Not logged in - redirect to /login")
flash ("Well that was wrong. Chicken winner. No more dinner.")
return redirect(url_for('login'))
print ("Logged in, do what needs to be done.")
return func(*args, **kwargs)
return decorator
Routes need an endpoint name, and if you don't specify one explicitly, Flask uses the name of the function (from functionobj.__name__). But your decorator wrapper object has the name decorator, so if you use the decorator more than once Flask complains that it already has used that endpoint name.
#functools.wraps() copies across the __name__ attribute, so now your decorator wrapper is also called funfunfun, whereas another decorated route function gets to keep its name too.

How to stub a super() call with Sinon

I am using Coffeescript and I'm testing using Sinon.js. When testing a method that invokes the method it overwrites, how can I stub the call to super()?
E.g., the method I want to test (a backbone.js model):
class Whatever extends Model
validate: (attributes) ->
validationErrors = super(attributes)
...
validationErrors
In the example, I want to make sure that super() is invoked with the given attributes and that validate returns the validation errors super() returns.
Like this:
it 'calls super and returns its result', ->
whatever = new Whatever()
attributes = sinon.stub()
superValidateStub = sinon.mock(Whatever.__super__)
superValidateStub.expects('validate').withExactArgs(attributes).returns('VALIDATION_RESULT')
expect(whatever.validate(attributes)).to.eql('VALIDATION_RESULT')
superValidateStub.verify()
Hope this helps anyone.

Tastypie Urls and Filters

I would like to use tastypie with some slightly different urls. I would like them to be like this:
/api/v1/city/London/make_default
/api/v1/city/Paris/make_default
/api/v1/city/Singapore/remove_city
Where the city itself can be any city in the city table in my db and the resource name is the method I want to perform. Each method has it's own resource. In tastypie the urls seem to give me some trouble with this. The prepend_urls that I have keep giving me a 301 redirect.
class CityResource(Resource):
class Meta
def make_default(self, request, city_name):
return super(ViewTemplateResource, self).get_object_list(request)\
.filter(name=city_name, client=request.user).update(default=True)
def prepend_urls(self):
return [
url(r"^city/(?P<city_id>[\w\d_.-]+)/(?P<resource_name>%s)/$" % self._meta.resource_name,
self.wrap_view('make_default')),
]
So to solve this I did it a bit differently:
first the wrap view was avoiding the normal pathway of tastypie instead of adding to it:
def dispatch_default(self, request, city_name, **kwargs):
self.queryset = City.objects.filter(name=city_name, client=user)
return self.dispatch('detail', request, **kwargs) # could use super here too instead of copying the normal code
def prepend_urls(self):
return [
url(r"^city/(.+)/(?P<resource_name>%s)$" % self._meta.resource_name,
self.wrap_view('dispatch_detail')),
]

Django-Nonrel with Mongodb listfield

I am trying to implement manytomany field relation in django-nonrel on mongodb. It was suggessted at to:
Django-nonrel form field for ListField
Following the accepted answer
models.py
class MyClass(models.Model):
field = ListField(models.ForeignKey(AnotherClass))
i am not sure where the following goes, it has been tested in fields.py, widgets,py, models.py
class ModelListField(ListField):
def formfield(self, **kwargs):
return FormListField(**kwargs)
class ListFieldWidget(SelectMultiple):
pass
class FormListField(MultipleChoiceField):
"""
This is a custom form field that can display a ModelListField as a Multiple Select GUI element.
"""
widget = ListFieldWidget
def clean(self, value):
#TODO: clean your data in whatever way is correct in your case and return cleaned data instead of just the value
return value
admin.py
class MyClassAdmin(admin.ModelAdmin):
form = MyClassForm
def __init__(self, model, admin_site):
super(MyClassAdmin,self).__init__(model, admin_site)
admin.site.register(MyClass, MyClassAdmin)
The following Errors keep popping up:
If the middle custom class code is used in models.py
name 'SelectMultiple' is not defined
If custom class code is taken off models.py:
No form field implemented for <class 'djangotoolbox.fields.ListField'>
You just need to import SelectMultiple by the sound of it. You can put the code in any of those three files, fields.py would make sense.
Since it's pretty usual to have:
from django import forms
at the top of your file already, you probably just want to edit the code below to:
# you'll have to work out how to import the Mongo ListField for yourself :)
class ModelListField(ListField):
def formfield(self, **kwargs):
return FormListField(**kwargs)
class ListFieldWidget(forms.SelectMultiple):
pass
class FormListField(forms.MultipleChoiceField):
"""
This is a custom form field that can display a ModelListField as a Multiple Select GUI element.
"""
widget = ListFieldWidget
def clean(self, value):
#TODO: clean your data in whatever way is correct in your case and return cleaned data instead of just the value
return value
You probably also want to try and learn a bit more about how python works, how to import modules etc.