Hi Everyone I'm just searching for the feature of Flask.
What I want to do is to branch controller with query-parameter like Spring #RequestMapping EXAMPLE
I want Flask Controller to work when specific params exist.
Do that features exist In Flask?
I don't want to branch with if statement in method
I dont want to like this.
from flask import request
#app.route('/user')
def user():
actions = request.args.get('actions')
if actions == "migration"
pass
if actions == "something"
pass
....
I want to like this
#app.route('/user', params={"actions=migration"})
def user_migration():
pass
#app.route('/user', params={"actions=something"})
def user_something():
pass
You can just add that logic in your "controller" itself, like so:
from flask import request
#app.route('/home/fetch')
def data():
# here we want to get the value of user (i.e. ?personId=some-value)
personId = request.args.get('personId')
if personId == <your-value-here>
If you know what your params are always going to be then why not just set it to the route itself:
#app.route('/user/migration')
def user_migration():
pass
#app.route('/user/something')
def user_something():
pass
Related
I'm building a project and now I'm new to VueJS I'm currently learning it. and I found that you can make HTTP Requests on APIs using axios. And to make my project easy, Can I call functions on my views.py thru axios?
Like I'm fetching urls in urls.py to execute some functions on my backend.
Is it okay? I mean for security and best practices. etc.
Thanks
Absolutely ok, that's what Django is for:
urls.py:
urlpatterns = [
...
path('my_view_function/', views.my_view_function, name='my_view_function'),
...
]
views.py:
def my_view_function(request):
# unpack data:
my_value = request.GET['my_key']
# some logic:
...
# pack response:
response = json.dumps({
'some_other_key' : 'some_other_value'
})
return HttpResponse(response)
Another option is that you use signals in django, some time ago I used signals that for when a new record is created without a field, it will be completed with the algorithm you want, for example an order and automatically placed a code, you can apply it only by pointing to your models, when you want something more punctual.
#receiver(pre_save, sender=MyModel)
def my_handler(sender, **kwargs):
...
The my_handler function will only be called when an instance of MyModel is saved.
Here I leave the documentation in case you want to review it
https://docs.djangoproject.com/en/3.1/topics/signals/
I'm using pytest with Flask and want to test my views and templates but I'm unclear how best to do this.
I'm aware I can test the contents of the HTML output, e.g.:
def test_my_view(test_client):
# test_client is a fixture representing app.test_client()
response = test_client.get("/my-url")
assert b"<h1>My page title</h1>" in response.data
But there are things I'm not sure how best to do:
How do I test which template is being used by the view?
How do I test the context the view sends to the template? (e.g. check that login_form is an instance of LoginForm)
If I want to test that a more complex HTML tag is present, say a <form> tag with the correct action attribute, is the only way to check for the presence of the entire tag (e.g. <form method="get" class="form-lg" action="/other-url">) even if I'm not bothered about other attributes? How could I just check for the action, assuming other forms are on the page too?
I've realised that 1 and 2 can be solved by a solution like the one in this question, slightly altered for use with pytest.
Let's say we have this Flask view:
from flask import render_template
from app import app
#app.route("/my/view")
def my_view():
return render_template("my/template.html", greeting="Hello!")
We want to test that calling that URL uses the correct template, and that has the correct context data passed to it.
First, create a reusable fixture:
from flask import template_rendered
import pytest
#pytest.fixture
def captured_templates(app):
recorded = []
def record(sender, template, context, **extra):
recorded.append((template, context))
template_rendered.connect(record, app)
try:
yield recorded
finally:
template_rendered.disconnect(record, app)
I also have a test_client fixture for making requests in tests (something like the testapp fixture in Flask Cookiecutter or the test_client fixture in this tutorial).
Then write your test:
def test_my_view(test_client, captured_templates):
response = test_client.get("/my/view")
assert len(captured_templates) == 1
template, context = captured_templates[0]
assert template.name = "my/template.html"
assert "greeting" in context
assert context["greeting"] == "Hello!"
Note that you might have more than one element in captured_templates, depending on what your view does.
I have a flask-RESTful endpoint defined by:
class SearchEvents(Resource):
def get(self, name, start_date, end_date):
#do stuff
api.add_resource(endpoints.SearchEvents, '/events/<string:name>/<string:start_date>/<string:end_date>')
I'm testing it manually with Postman. I'd like to pass in null values for start_date and end_date. However:
I've tried modifying the url to:
http://127.0.0.1:5000/events/test/ / #<--Spaces
and
http://127.0.0.1:5000/events/test/""/""
To no avail.
Ended up solving this by using the flask-restful request object, which has an args property which retrieves query params from the request url:
from flask_restful import request #import request from flask restful
class SearchEvents(Resource):
def get(self):
args = request.args #retrieve args from query string
api.add_resource(endpoints.SearchEvents, '/events')
And then making the requests like: http://127.0.0.1:5000/events?param1=value1¶m2=value2
Or to pass null values: http://127.0.0.1:5000/events?param=¶m2=value1
The values you are passing are not in the query string. You are using route parts as parameters so the route does not get matched unless you supply something of the form /events/some_name/2019-86-98/2100-9885-24515. The attempts you made are catched by flask as non matching routes and you get 404 not found.
To send those parameters as part of the query string would be to use something like
/events?name=some_name&start_date=2019-86-98&end_date=2100-9885-24515 and to get the values in your route handlers you should use name = request.args.get('name') and so on. Passing null values then means hitting the same url but without the query parameters.
The cache system I'm using (Flask-Cache) uses URLs to calculate cache keys. From a different place in the code I get passed a view function, and then need to check if the view has been cached.
Firstly, the current iteration of Flask-Cache needs the request to calculate the cache key, but I have made a patch that fixes the deficiency for simple cases, by getting the URL with url_for(view_function.__name__, **kwargs).
The problem is that now I've started using Flask Blueprints, and simply using view_function.__name__ in url_for will not find the blueprint route (raises BuildError).
Simple Flask app
#app.route('/user/<user_id>')
def user_page(user_id):
return 'Hello user %s' % user_id
def check_cache(view_function, **kwargs):
url = url_for(view_function.__name__, **kwargs)
... use URL to check cache ...
check_cache(user_page, user_id='123')
Blueprint Flask app
from flask import Blueprint
bp = Blueprint('user_blueprint', __name__)
#bp.route('/user/<user_id>')
def user_page(user_id):
return 'Hello user %s' % user_id
def check_cache(view_function, **kwargs):
url = url_for(view_function.__name__, **kwargs) # WON'T WORK WITH BLUEPRINTS
... use URL to check cache ...
check_cache(user_page, user_id='123')
How do I get the URL for the route/view function, when it's defined via a Blueprint?
Or alternatively, how do I make cache keys that will work when using blueprints? (And can be calculated via a decorator on a view function, and doesn't clash when two or more blueprints have view functions with the same name)
Blueprints, by default, prepend the endpoint name with the blueprint name. In this way, the url_for string:
url = url_for('user_page')
Becomes:
url = url_for('user_blueprint.user_page')
Now, you are creating your url_for strings with the function name, so you can either switch to explicitly passing the endpoint strings as above, or use:
url = url_for('user_blueprint.' + view_function.__name__)
I don't know of a programmatic way to automatically find the blueprint name from the view_function.
Try with app.view_functions
def check_cache(view_function, **kwargs):
flipped_view_functions_dict = dict((v, k) for k, v in app.view_functions.iteritems())
view_name = flipped_view_functions_dict[view_function]
url = url_for(view_name, **kwargs)
... use URL to check cache ...
I have a function which i call from a unittest. From setting some debug traces i know the function worked like a charm and has all the values correctly prepared for return.
This is what my testcode looks like (see where my ipdb.set_trace() is ):
#override_settings(REGISTRATION_OPEN=True)
def test_confirm_account(self):
""" view that let's a user confirm account creation and username
when loggin in with social_auth """
request = self.factory.get('')
request.user = AnonymousUser()
request.session={}
request.session.update({self.pipename:{'backend':'facebook',
'kwargs':{'username':'Chuck Norris','response':{'id':1}}}})
# this is the function of which i need the context:
response = confirm_account(request)
self.assertEqual(response.context['keytotest'],'valuetotest')
From what i know from this part of the Django docs, i would be able to access response.context when i have used the testing client. But when i try to access response.context like i did it, i get this:
AttributeError: 'HttpResponse' object has no attribute 'context'
Is there a way to get the special HttpResponse object of the client, without using the client?
The RequestFactory does not touch the Django middleware, and as such, you will not generate a context (i.e. no ContextManager middleware).
If you want to test the context, you should use the test client. You can still manipulate the construction of the request in the test client either using mock or simply saving your session ahead of time in the test, such as:
from django.test import Client
c = Client()
session = c.session
session['backend'] = 'facebook'
session['kwargs'] = {'username':'Chuck Norris','response':{'id':1}}
session.save()
Now when you load the view with the test client, you'll be using the session as you set it, and when you use response = c.get('/yourURL/'), you can then reference the response context using response.context as desired.
The "response.context" is incorrect for new django versions but you can use response.context_data to get the same context that passed to TemplateResponse.
Though this is an old post, I suppose this tip can be of help. You can look into using TemplateResponse (or SimpleTemplateResponse) which can be substituted for render or render_to_response.
The Django docs has more on this
Yes, you can. You have to patch render.
I'm using pytest-django
class Test:
def context(self, call_args):
args, kwargs = call_args
request_mock, template, context = args
return context
#patch('myapplication.views.render')
def test_(self, mock_render, rf):
request = rf.get('fake-url')
view(request)
context = self.context(mock_render.call_args)
keytotest = 'crch'
assert keytotest == context['keytotest']
context (sic!) can be found in Response class. As you see it says it's HTTPResponse you get back from the view function. This happened because you've called it directly. Call this function via test client and it will be okay.
response = client.get('/fobarbaz/')
response.context