How to use query results in url regex in Django - regex

I want to use a database query to generate my URL configuration. Something like:
states = State.objects.all().values_list('pk', flat=True)
And then a regex like:
(r'^state/(?P<state>' + '|'.join(states) + ')/$'
The idea is that I can have URLs like:
/state/ca/
/state/az/
Etc.
The problem is that when I do syncdb, the query above fails, throwing a DatabaseError.
Is there a good way to do this? I've tried the obvious change, which would be:
try:
states = State.objects.all().values_list('pk', flat=True)
except DatabaseError:
# First sync, use dummy data
states = []
But this doesn't work because the exception is thrown at the regex, not at the query definition.
Ideas?

Why do you need to constrain this in the URL pattern itself? Much better to accept all two-letter codes, and check in the view.
(r'^state/(?P<state_code>\w{2})/$'
def view_state(request, state_code):
state = get_object_or_404(State, pk=state_code)

Related

Why is Django Paramaterized query not working

I have been struggling with this simple query in django. I have checked a lot over internet. I tried using similar syntax - yet no luck.
In my application on html page I need to display some specific record. And for that i want to use parameterized select statement. But the query is not working..
I have checked id2 is getting correct value from previous html page..
And I know I can use APIs but for my databases classes I need to use raw queries in my application.
Can someone please help me here...
def details(request, id2):
temp = 'test3'
data = Posts.objects.raw('''select * from posts_posts where posts_posts.id = %s ''', id2)
context ={
'post' : data,
If you run that code you will see an error, since that is not the correct format for a call to raw. If you can't see the error output anywhere, then you have yet another problem for another post.
The correct format for raw is: .raw(sql, iterable-values), like this:
posts = Posts.objects.raw("select * ..", [id2, ]) # or use (id2,) for a tuple
<RawQuerySet: select * from ... where id = 5>
To get the actual list, since that just gives you a Query, you need to evaluate it somehow:
posts_list = list(posts)
first_post = posts[0]
Be careful, if you don't evaluate the QuerySet then it can be re-run a second time. Please convert it to a list() before doing further operations on it.

email__iexact on django doesn't work on postgresql?

Calling UserModel.objects.filter(email__iexact=email) results in the following query
SELECT * FROM "accounts_person" WHERE "accounts_person"."email" = UPPER('my-email#mail.com')
This doesn't find anything because it there's no EMAIL#MAIL.COM in the database, only email#mail.com. Shouldn't the query have been translated to
WHERE UPPER("accounts_person"."email") = UPPER('my-email#mail.com')?
Summary:
UserModel.objects.filter(email=email) # works
UserModel.objects.filter(email__exact=email) # works
UserModel.objects.filter(email__iexact=email) # doesn't work
Clash you ae right this i also faced the same situtaion with postgres sql .
If you go through This ticket
You will get some idea .
Perhaps an option could be passed to EmailField to state whether you want it to lower all case or not. It would save having to do something in the form validation like.
def clean_email(self):
return self.cleaned_data['email'].lower()
My bad. I had patched lookup_cast to be able to use the unaccent module on postgresql and ended up not calling the original lookup_cast afterwards. The generated query now looks like this WHERE UPPER("accounts_person"."email"::text) = UPPER('my-email#mail.com'). This is the default behavior on django.

case insensitive query using generic views

I would like my urls to be case insensitive. Adding (?i) to the beginning of the regexp in urls.py does not work completely when using generic views.
Here is the url that I'd like to focus on:
url(r'^(?i)(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\w{1,2})/(?P<slug>[-A-Za-z0-9_]+)/$', BlogDateDetailView.as_view(model=Entry,
queryset=Entry.objects.all(),
date_field='pub_date',
slug_field='slug',
)),
The following work:
http://mysite.com/2012/jan/24/my-article
http://mysite.com/2012/JAN/24/my-article
The following does not work (i.e I get a 404):
http://mysite.com/2012/jan/24/My-Article
I think the reason it does not work is because the lookup query for the slug is case sensitive. In order to make this work, I believe I need to subclass (not sure if this is the right term) class SingleObjectMixin(object): since this is where queryset = queryset.filter(**{slug_field: slug}) happens. Perhaps I should subclass get_queryset().
I'd appreciate some guidance on how I could do this cleanly in django 1.3
Case-insensitivity in URLs is generally a bad thing. A resource should only really have one URL.
However, you can just use:
slug_field='slug__iexact'
But, I would instead catch the DoesNotExist exception, lower() the slug from the URL, try the query again with the new slug and return a redirect to the correct URL. You could actually check for uppercase letters before running the first query to avoid running unnecessary ones.
It's up to you :)

Django taggit doesn't work exclude

I am using Django-taggit and works fine for me but the exclude has a problem.
Keyword is a string like 'key1 key2 key3'. The code is:
keyword = form.cleaned_data['keyword']
qlist = lambda x: [Q(name__icontains=x), Q(author__name__icontains=x),Q(tags__name__icontains=x)]
item_list = Item.objects.distinct()
for key in keyword.split():
if ('-'==key[0]):
print 'exclude: %s'%(key[1:])
item_list = item_list.exclude(reduce(operator.or_,qlist(key[1:])))
else:
print 'include: %s'%(key)
item_list = item_list.filter(reduce(operator.or_,qlist(key)))
It works fine for filter() and for the exclude() Q(name_icontains=x), Q(author_name_icontains=x).
But, when I try to use exclude() with Q(tags_name__icontains=x) it doesnt work.
Regards,
Cristian
I'm not really too versed in taggit intricacies, but... Looking at the code, it seems like the "name" is dynamically built in a lazy way.
So, if you're not populating the query explicitly, you're going to get empty request, so Q(tags__name__icontains=key) will be empty, and exclude(...) will just be like filter(not null).
Try to force populating the tag query via a select_related() or something similar.
I think, It is not supported. I found this link:
https://github.com/alex/django-taggit/issues/31

Capturing URL parameters in request.GET

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."