There's some way to return items that field contains some value? Eg.
GET /people?contains="foo"
Return all persons that have the word 'foo' in the name.
Thanks in advance
You could use mongodb $regex operator, which is blacklisted by default in Eve (MONGO_QUERY_BLACKLIST = ['$where', '$regex']).
Add MONGO_QUERY_BLACKLIST = ['$where'] to your settings.py. Then you can query your API like this:
?where={"name": {"$regex": ".*foo.*"}}.
Be careful however. If you don't control the client, enabling regexes could potentially increase your API vulnerability.
I am not conversant with Eve myself. But looking at it's webpage seems like it exposes all of Flask's functionalities.
You need to be looking at this page in the documentation that talks about accessing the request data.
In your Flask app, define a method that accepts both POST and GET requests and then you can access foo by doing request.args.get('contains', '').
This is what I mean:
#app.route('/people', methods=['POST', 'GET'])
def get_people():
search_key = request.args.get('contains', '')
#search for people containing 'foo' in your DB
Hope this gives you a starting point as to how to go about things.
Related
I'm going nuts trying to access the properties of a Datastore query. I could not find anything in the documentation (it could be me).
In the datastore I have the following:
Here's a snippet of my main.py:
import all the necessary stuff
...
datastore_client = datastore.Client()
u_name = 'batman' # example of the user I want to find
qn = datastore_client.query(kind='user').add_filter('user_id', '=', u_name).fetch()
So far so good, but how do I access the properties of this query?
What I haven't been able to find is how do I access the first_name of user 'batman'?
Something like:
name = qn.somefuntion('first_name')
Could someone tell me how to do this and also point me to the respective documentation?
Thanks!
Check out the python library reference for an Entity. The key part there is "you can treat an entity like a regular Python dictionary."
for entity in qn:
print(entity['first_name'])
From Nicola's SO answer here and my own testing it seems clear that Eve does not support conditional deletes at resource endpoints.
I know I could use a GET: "where={...}" request to the _ids and _etags of the documents I would like to delete, and then send out a series of requests at each item endpoint to delete them with the If-Match header appropriately set to each item's _etag:
for each item:
DELETE: http://localhost:5000/items/<item._id>
...but I would like to avoid sending out multiple HTTP requests if possible.
One solution may be predefined database filters, but these would be static filters where I'd like to dynamically filter deletion depending on some URL parameters. Pre-event hooks may be the solution I'm seeking.
Does Eve support bulk deletion? And if not, what is the recommended way to extend Eve's functionality to provide conditional and/or bulk deletes?
I added a pre-event hook to DELETE, and this seems to be working with the tests I've run so far:
def add_delete_filters(resource, request, lookup):
if 'where' in request.args:
conditions = request.args.getlist('where')
for cond_str in conditions:
cond = json.loads(cond_str)
for attrib in cond:
lookup[attrib] = cond[attrib]
app = Eve()
app.on_pre_DELETE += add_delete_filters
While reading someone's code in Python/Flask, I came across the line:
results = Page.query.filter(Page.url.contains(url))
I've searched it but can't get a satisfying answer. What do the functions query.filter and url.contains do exactly and what values they return under different conditions like if there are no matches or multiple matches or table doesn't exist. Is page the name of the table or just the name of the class?
Edit: Function in which the line is used
#pages.route('/<url>/', methods=('GET', 'POST'))
def url_view(url):
from app import get_locale
page = DataGetter.get_page_by_url('/' + url, get_locale())
return render_template('gentelella/guest/page.html', page=page)
def get_page_by_url(url, selected_language=False):
if selected_language:
results = Page.query.filter_by(language=selected_language).filter(Page.url.contains(url))
else:
results = Page.query.filter(Page.url.contains(url))
if results:
return results.first()
return results
I think you need to do a bit more research on your own, but to get you started this looks like a Flask-SQLAlchemy project which is a Flask around the SQLAlchemy library. The documentation you need to read is mostly in SQLAlchemy and Flask-SQLAlchemy.
Page appears to be a ORM mapping of a database table. The filter/filter_by methods encapsulates the SQL SELECT functionality. The contains method encapsulates the SQL LIKE %<OTHER>% functionality.
I have a resource in eve e.g. ABC, I want to manipulate another resource e.g. BCD when some condition meet while I am posting a new item to ABC, I know I can hook the event for post/pre_POST_ABC but is there a 'internal' way to do post on BCD without going through via the HTTP again?
In your callback function you could either:
A) use the data driver to store data directly to the database
Something like this:
def update_ABC(request, payload):
accounts = app.data.driver.db['abc_collection']
account = accounts.insert(docs)
app = Eve()
app.on_post_POST_ABC += update_ABC
app.run()
Would do the trick. You would be bypassing the framework this way, and storing directly on the database.
B) Use app.test_client.post() to POST through directly through the application.
app.test_client().post('/bcd', json.dumps({"field":"value"}, content_type='application_json'))
This is probably a better option since the request goes through the framework (meta fields like data_created are handled for you.)
Update: With v0.5+ you can now use post_internal to achieve the same result. There are equivalent internal methods available for other CRUD methods as well.
my question is quite hard to describe, so I will focus on explaining the situation. So let's say I have 2 different entities, which may run on different machines. Let's call the first one Manager and the second one Generator. The manager is the only one which can be called via the user.
The manager has a method called getVM(scenario_Id), which takes the ID of a scenario as a parameter, and retrieve a BLOB from the database corresponding to the ID given as a parameter. This BLOB is actually a XML structure that I need to send to the Generator. Both have a Flask running.
On another machine, I have my generator with a generateVM() method, which will create a VM according to the XML structure it recieves. We will not talk about how the VM is created from the XML.
Currently I made this :
Manager
# This method will be called by the user
#app.route("/getVM/<int:scId>", methods=['GET'])
def getVM(scId):
xmlContent = db.getXML(scId) # So here is what I want to send
generatorAddr = sgAdd + "/generateVM" # sgAdd is declared in the Initialize() [IP of the Generator]
# Here how should I put my data ?
# How can I transmit xmlContent ?
testReturn = urlopen(generatorAddr).read()
return json.dumps(testReturn)
Generator
# This method will be called by the user
#app.route("/generateVM", methods=['POST'])
def generateVM():
# Retrieve the XML content...
return "Whatever"
So as you can see, I am stuck on how to transmit the data itself (the XML structure), and then how to treat it... So if you have any strategy, hint, tip, clue on how I should proceed, please feel free to answer. Maybe there are some things I do not really understand about Flask, so feel free to correct everything wrong I said.
Best regards and thank you
PS : Lines with routes are commented because they mess up the syntax coloration
unless i'm missing something couldn't you just transmit it in the body of a post request? Isn't that how your generateVM method is setup?
#app.route("/getVM/<int:scId>", methods=['GET'])
def getVM(scId):
xmlContent = db.getXML(scId)
generatorAddr = sgAdd + "/generateVM"
xml_str = some_method_to_generate_xml()
data_str = urllib.urlencode({'xml': xml_str})
urllib.urlopen(generatorAddr, data=data_str).read()
return json.dumps(testReturn)
http://docs.python.org/2/library/urllib.html#urllib.urlopen