I'm new to python and I am sure there's a better way to do this. For my specific issue I have stored an API key. I've given the user means to send an argument with a new API key if needed. Otherwise the argument is set as False. So if the user sends an API key, I first want to find out if it's different from the one I already have. And if it is different I then want to update it in my secret manager.
There's one addtl layer of possible complication. It's a header in a webhook.
So I'm writing an if function but it feels very inelegant. This is what I currently have written. I'm also using Flask, hence request.
This is my code:
if request.headers['x-api-key'] and request.headers['x-api-key'] not in stored_api_key:
# do something
Would love to know how I should be writing this. Thank you.
Flask's request.headers acts like a dictionary, and so if you do
request.headers['x-api-key']
And the key x-api-key does not exist in the user's request, this will throw an error. Similar to dict, you can use the .get() method to default to a value in the case it does not exist. In this case, your code would look like so:
api_key = request.headers.get('x-api-key')
if api_key and api_key not in stored_api_key:
# do something
Otherwise, you must do the following:
if 'x-api-key' in request.headers and request.headers['x-api-key'] not in stored_api_key:
I wouldn't try to jam this into a single if statement. You have two checks where one check can use the output of the last. IMO it reads much more clearly to me to have two if statements. You could use an assignment expression to help simplify your logic:
if api_key := request.headers.get('x-api-key'):
if api_key not in stored_api_key:
...
The first if assigns api_key and checks for truthiness. get is used to avoid KeyErrors. The second if uses the value from above where we know api_key is not None.
You could also one liner this if you really want to, but is definitely less readable:
if (key := request.headers.get('x-api-key')) and key not in stored_api_key:
...
I am currently defining regular expressions in order to capture parameters in a URL, as described in the tutorial. How do I access parameters from the URL as part the HttpRequest object?
My HttpRequest.GET currently returns an empty QueryDict object.
I'd like to learn how to do this without a library, so I can get to know Django better.
When a URL is like domain/search/?q=haha, you would use request.GET.get('q', '').
q is the parameter you want, and '' is the default value if q isn't found.
However, if you are instead just configuring your URLconf**, then your captures from the regex are passed to the function as arguments (or named arguments).
Such as:
(r'^user/(?P<username>\w{0,50})/$', views.profile_page,),
Then in your views.py you would have
def profile_page(request, username):
# Rest of the method
To clarify camflan's explanation, let's suppose you have
the rule url(regex=r'^user/(?P<username>\w{1,50})/$', view='views.profile_page')
an incoming request for http://domain/user/thaiyoshi/?message=Hi
The URL dispatcher rule will catch parts of the URL path (here "user/thaiyoshi/") and pass them to the view function along with the request object.
The query string (here message=Hi) is parsed and parameters are stored as a QueryDict in request.GET. No further matching or processing for HTTP GET parameters is done.
This view function would use both parts extracted from the URL path and a query parameter:
def profile_page(request, username=None):
user = User.objects.get(username=username)
message = request.GET.get('message')
As a side note, you'll find the request method (in this case "GET", and for submitted forms usually "POST") in request.method. In some cases, it's useful to check that it matches what you're expecting.
Update: When deciding whether to use the URL path or the query parameters for passing information, the following may help:
use the URL path for uniquely identifying resources, e.g. /blog/post/15/ (not /blog/posts/?id=15)
use query parameters for changing the way the resource is displayed, e.g. /blog/post/15/?show_comments=1 or /blog/posts/2008/?sort_by=date&direction=desc
to make human-friendly URLs, avoid using ID numbers and use e.g. dates, categories, and/or slugs: /blog/post/2008/09/30/django-urls/
Using GET
request.GET["id"]
Using POST
request.POST["id"]
Someone would wonder how to set path in file urls.py, such as
domain/search/?q=CA
so that we could invoke query.
The fact is that it is not necessary to set such a route in file urls.py. You need to set just the route in urls.py:
urlpatterns = [
path('domain/search/', views.CityListView.as_view()),
]
And when you input http://servername:port/domain/search/?q=CA. The query part '?q=CA' will be automatically reserved in the hash table which you can reference though
request.GET.get('q', None).
Here is an example (file views.py)
class CityListView(generics.ListAPIView):
serializer_class = CityNameSerializer
def get_queryset(self):
if self.request.method == 'GET':
queryset = City.objects.all()
state_name = self.request.GET.get('q', None)
if state_name is not None:
queryset = queryset.filter(state__name=state_name)
return queryset
In addition, when you write query string in the URL:
http://servername:port/domain/search/?q=CA
Do not wrap query string in quotes. For example,
http://servername:port/domain/search/?q="CA"
def some_view(request, *args, **kwargs):
if kwargs.get('q', None):
# Do something here ..
For situations where you only have the request object you can use request.parser_context['kwargs']['your_param']
You have two common ways to do that in case your URL looks like that:
https://domain/method/?a=x&b=y
Version 1:
If a specific key is mandatory you can use:
key_a = request.GET['a']
This will return a value of a if the key exists and an exception if not.
Version 2:
If your keys are optional:
request.GET.get('a')
You can try that without any argument and this will not crash.
So you can wrap it with try: except: and return HttpResponseBadRequest() in example.
This is a simple way to make your code less complex, without using special exceptions handling.
I would like to share a tip that may save you some time.
If you plan to use something like this in your urls.py file:
url(r'^(?P<username>\w+)/$', views.profile_page,),
Which basically means www.example.com/<username>. Be sure to place it at the end of your URL entries, because otherwise, it is prone to cause conflicts with the URL entries that follow below, i.e. accessing one of them will give you the nice error: User matching query does not exist.
I've just experienced it myself; hope it helps!
These queries are currently done in two ways. If you want to access the query parameters (GET) you can query the following:
http://myserver:port/resource/?status=1
request.query_params.get('status', None) => 1
If you want to access the parameters passed by POST, you need to access this way:
request.data.get('role', None)
Accessing the dictionary (QueryDict) with 'get()', you can set a default value. In the cases above, if 'status' or 'role' are not informed, the values are None.
If you don't know the name of params and want to work with them all, you can use request.GET.keys() or dict(request.GET) functions
This is not exactly what you asked for, but this snippet is helpful for managing query_strings in templates.
If you only have access to the view object, then you can get the parameters defined in the URL path this way:
view.kwargs.get('url_param')
If you only have access to the request object, use the following:
request.resolver_match.kwargs.get('url_param')
Tested on Django 3.
views.py
from rest_framework.response import Response
def update_product(request, pk):
return Response({"pk":pk})
pk means primary_key.
urls.py
from products.views import update_product
from django.urls import path
urlpatterns = [
...,
path('update/products/<int:pk>', update_product)
]
You might as well check request.META dictionary to access many useful things like
PATH_INFO, QUERY_STRING
# for example
request.META['QUERY_STRING']
# or to avoid any exceptions provide a fallback
request.META.get('QUERY_STRING', False)
you said that it returns empty query dict
I think you need to tune your url to accept required or optional args or kwargs
Django got you all the power you need with regrex like:
url(r'^project_config/(?P<product>\w+)/$', views.foo),
more about this at django-optional-url-parameters
This is another alternate solution that can be implemented:
In the URL configuration:
urlpatterns = [path('runreport/<str:queryparams>', views.get)]
In the views:
list2 = queryparams.split("&")
url parameters may be captured by request.query_params
It seems more recommended to use request.query_params. For example,
When a URL is like domain/search/?q=haha, you would use request.query_params.get('q', None)
https://www.django-rest-framework.org/api-guide/requests/
"request.query_params is a more correctly named synonym for request.GET.
For clarity inside your code, we recommend using request.query_params instead of the Django's standard request.GET. Doing so will help keep your codebase more correct and obvious - any HTTP method type may include query parameters, not just GET requests."
def frontblog(request):
if request.method=='POST':
for post in Posts.objects(tags=request.POST('search')):
posttitle=post.post_title
postcont=post.post_content
postdate=post.post_date
posttag=post.post_tags
return render_to_response("frontblog.html",
RequestContext(request,
{'post':post}))
I have tried to send the data from mongo db database as by search using tag post get retrieved and should be send to display on html page.
NB : answer based on badly indented code, so it's a bit of a guessing game... but if you want a correct answer learn to post correctly indented code.
You start your code with a test on request.method=='POST' and everything else is under that branch, which means that if it's a GET request (or PUT or whatever) your view function implicitely returns None.
There are quite a few other WTFs in your code but fix this one first. BTW a "search" should be done as GET request, not POST. Also, in a POST request, request.GET will most probably be empty. Finally, you DO want to use a Form to sanitize user inputs... Well, unless you don't mind your site or app being hacked by the first script-kiddie, that is.
As a Flask beginner, I can't understand how request.args is used. I read somewhere that it is used to return values of query string (correct me if I'm wrong) and how many parameters request.args.get() takes.
I know that when I have to store submitted form data, I can use fname = request.form.get("firstname"). Here, only one parameter is passed, whereas the code below takes two parameters.
#app.route("/")
def home():
cnx = db_connect()
cur = cnx.cursor()
output = []
page = request.args.get('page', 1)
try:
page = int(page)
skip = (page-1)*4
except:
abort(404)
stmt_select = "select * from posts limit %s, 4;"
values=[skip]
cur.execute(stmt_select,values)
x=cur.fetchall()
for row in reversed(x):
data = {
"uid":row[0],
"pid":row[1],
"subject":row[2],
"post_content":row[3],
"date":datetime.fromtimestamp(row[4]),
}
output.append(data)
next = page + 1
previous = page-1
if previous<1:
previous=1
return render_template("home.html", persons=output, next=next, previous=previous)
Please explain why it takes two parameters, and then what its use is.
According to the flask.Request.args documents.
flask.Request.args
A MultiDict with the parsed contents of the query string. (The part in the URL after the question mark).
So the args.get() is method get() for MultiDict, whose prototype is as follows:
get(key, default=None, type=None)
In newer version of flask (v1.0.x and v1.1.x), flask.Request.args is an ImmutableMultiDict(an immutable MultiDict), so the prototype and specific method above are still valid.
As a newbie using Flask and Python myself, I think some of the other answers here take for granted that you have a good understanding of the fundamentals. In case you or other readers don't, I'll give more context
... request.args returns a "dictionary" object for you. The "dictionary" object is similar to other collection-type of objects in Python, in that it can store many elements in one single object. Therefore the answer to your question
And how many parameters request.args.get() takes.
It will take only one object, a "dictionary" type of object (as stated in the previous answers). This "dictionary" object, however, can have as many elements as needed... (dictionaries have paired elements called Key, Value).
Other collection-type of objects besides "dictionaries", would be "tuple", and "list"... you can run a google search on those and "data structures" in order to learn other Python fundamentals. This answer is based Python; I don't have an idea if the same applies to other programming languages.
It has some interesting behaviour in some cases that is good to be aware of:
from werkzeug.datastructures import MultiDict
d = MultiDict([("ex1", ""), ("ex2", None)])
d.get("ex1", "alternive")
# returns: ''
d.get("ex2", "alternative")
# returns no visible output of any kind
# It is returning literally None, so if you do:
d.get("ex2", "alternative") is None
# it returns: True
d.get("ex3", "alternative")
# returns: 'alternative'
request.args is a MultiDict with the parsed contents of the query string.
From the documentation of get method:
get(key, default=None, type=None)
Return the default value if the
requested data doesn’t exist. If type is provided and is a callable it
should convert the value, return it or raise a ValueError if that is
not possible.
I'm trying to gat the value of a form field in django, now
xxx = request.POST[u'a1']
gives me a value, but
xxx = request.POST.get(u'a1')
gives me nothing
what am I doing wrong?
Update:
Using the first method, request.method = POST,
using the second method changes it to GET,
all I am doing is replacing one line of code.
Ingmar, yes this does return true.
Shawn, first method produces DEBUG:root:[(u'a1', u'A1_6')],
second method produces DEBUG:root:[]
The get method takes two parameters: key and a return value for where there's no match for the key (defaults to None).
Maybe the first example worked only in cases where the form had a value in the field 'a1'.
Either set a return value for the get method (e.g. xxx = request.POST.get(u'a1', 'something')) or check in advance whether you have that field in the form (if u'a1' in request.POST ...)
A bit confusing question, but the way I understand you, you have a request that at one point contains a QueryDict with data in request.POST, but at a later point in the code cointains an empty QueryDict: {} in request.POST, and you are looking for the reason why and where the data disappears.
The Django docs say the QueryDict in HttpRequest is immutable, and cannot be changed. So you probably shouldn't be looking for code changing the value of the request.POST QueryDict, but some code that replaces the whole request.POST QueryDict with another one.
My guess is that you are assigning the value 'GET' to request.method at some point in the code, since you say that in function number two, request.method is changed to GET
When tinkering with a response of the type PUT some time ago I discovered that django actually applies logic to the HttpResponse object if response.method is changed, resulting in a changed request.POST QueryDict.