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.
I am new in web development in django i don't know when to use slug field and when to use query string parameters in the url.Can anyone suggest me practical differences between them.
Using slugs keep urls simple and clean, thereby easy to remember. Consider the following example:
example.com/post/hello-world/
v/s
example.com/?post=hello-world
Obviously, first one is cleaner.
But query string parameters have their uses too. For example, when you search for an object.
example.com/search/?q=hello-world
or when you need to pass multiple parameters
example.com/search/?q=hello+world&lang=en&something=else
In slug related django urls you have a url associated to a view. But you cannot pass querystring parameters to your views.
Ex -example.com/post/hello-world/ does not pass any parameter to your view function.
But if you want to pass additional parameters to your views, ex,
example.com/search/?q=hello-world
here q=hello-world is a query string parameter passed to your views.
And inside your views function you can get these parameters in request.GET
So your views function goes something like this
def helloworld():
qParams = request.GET.get('q', '')
....
....
Hope this helps.
I want to test redirection of Update View.
Reading the documentations, and looking at source code, I find:
Update View instances self.object before processing the request (which helps it to set form fields to current value)
Now this is behavior I wanted, but is giving me trouble during testing.
My Models.py
class Project(models.Model):
title = models.CharField(max_length=50)
description = models.CharField(max_length=200, blank=True, default="")
# Other fields
views.py
class UpdateProject(LogInRequiredMixin, UpdateView):
form_class = ProjectUpdateForm
template_name = 'project/create.html'
And In Testing:
(I have created a project and set up most things in setUp)
def test_redirection(self):
# After updating project, users should land on correct page.[View Project page].
self.client.login(username=self.owner.email, password=self.password)
response = self.client.post(self.url, follow=True) # This will give error, since it requires Title field
self.assertRedirects(response, reverse('project:show',
kwargs={'project_id': self.project.id}))
Now, I know I can pass title explicitly with data field, but if I were to change the fields later in model, this test would also fail, which it shouldn't [It's only purpose is to check for redirection, there are other tests which deal with form validation, etc]
So, my question is: Is there a way to simulate Post Request as done by Update View (i.e. pass data context by setting object context to pre-filled values and only over-ride changed values]
The view presumably only redirects on success. If you don't pass enough information for the view to succeed, then it shouldn't redirect. So it sounds like you want something impossible — you're wanting to test what the code does in a situation other than the situation you are setting up.
The question I have is: what is the value of this test? Why not just put it at the end of the test that checks for success?
I understand that the normal testing mantra is that you have a test for one thing only, but I think it's just impractical for this kind of scenario, and the cost is fragile tests that hack around the internals of something.
The other approach is that you split you write your tests like this:
def _submit_good_form_data(self):
response = self.client.post(self.url, follow=True, data={'title':'The title')
def test_form_success(self):
response = self._submit_good_data()
# asserts here
def test_redirection(self):
response = self._submit_good_data()
# asserts here
This way you only have one place to update when the nature of your form changes.
However, I'd question whether this is really worth it, seeing you are adding significantly to the length of the test run, and it doesn't actually give you the test independence you are really after (an error in the view will cause both tests to fail).
One way to replicate behind-the-scenes machinery:
get_response = self.client.get(self.url)
response = self.client.post(self.url, data=get_response.context['object'].__dict__, follow=True)
self.assertRedirects(response, reverse('project:show', kwargs={'project_id': self.project.id}))
Not very pretty, but is basically what goes behind the scenes.
This is less a technical question, more a "am i doing this in the right way" question.
I have several models defined
class Style(models.Model):
tag_xml = models.TextField()
image = models.ImageField(upload_to="styles")
user = models.ForeignKey(User)
uploaded = models.DateField()
class StyleMatch(models.Model):
style = models.ForeignKey(Style)
item = models.ForeignKey(FashionItem)
they can't be populated via html forms simply due to the nature of the task, so in order to populate them I have a html page with jquery and lots of event functions and other javascript goodies. When the save button is clicked I call .ajax() and pass all of the collected variables
var saveRequest= $.ajax({
url: "/save_style/",
type: "POST",
data: "selection="+s+"&user="+user+"&src="+image_src,
dataType: "text"
});
My save_style view then saves the values into the model
def save_style(request):
if request.method == 'POST':
selection = request.POST['selection'].rsplit("|")
user = request.POST['user']
src = request.POST['src']
f = open(MEDIA_ROOT+src)
image_file = File(f)
u = User.objects.get(id=user)
style = Style(tag_xml = "",
image = image_file,
user = u,
uploaded = date.today())
style.save()
for s in selection:
if (s != ''):
match = FashionItem.objects.get(id=s)
styleMatch = StyleMatch(style = style,
item = match)
styleMatch.save()
i = StyleMatch.objects.filter(style=style)
items = FashionItem.objects.filter(id__in=i)
return render_to_response('style_saved.html', dict(image=src, items=items, media_url = MEDIA_URL), context_instance=RequestContext(request))
After doing this I really want to go to a success page and display the records I have just added to the model, however if I use render_to_response and pass back the model details I have to rebuild the entire page in javascript, it seems better to redirect to a new template, but if I use HttpResponseRedirect a) I can't pass back values and b) it doesn't appear to be redirecting quite right (I think because the post is originating from my javascript).
So finally my questions
Is this really how I should be doing this? The django doc doesn't
really seem to cover these slightly more complicated areas, so I'm a
little unsure.
Should I be using render_to_response or
HttpResponseRedirect above? Or possibly a third option I don't know
about.
Any suggestions appreciated.
FYI I know the code above is not ideal i.e. missing validation, comments ... etc, its simply been provided for demonstration purposes. Feel free to point out any serious issues though.
Depending on the nature of your application, you probably shouldn't be building the entirety of your pages with JavaScript. However, since we're there already I've used the following solution with nice results:
Consider creating a template "fragment", as I call them. It's simply a bit of HTML that is designed to be a capsule for data transferred via AJAX. Do a render_to_response to this fragment, pass in your processed view data as variables, then retrieve this data via AJAX and use JavaScript to replace the HTML within a designated div element with the returned data.
There are some pitfalls with the above solution, such as styling and event handler attachment on the template fragment, but it should at least get you working. Just a tip in this regard, become familiar with jQuery's .on().
pass all of the collected variables
Why don't $(form).serialize()?
saves the values into the model
Why don't use django.forms.ModelForm (or few of them)?
doesn't appear to be redirecting quite right
Because redirects in AJAX are processed in AJAX call and do not affect opened page unless you process received data in JS somehow.
Also, you don't have any data validation and|or error reporting, that's bad. Actually, ModelForm should provide a huge help with that.