Django Postgres Case Insensitive Textfield and citext - django

for my Django app i use PostgreSQL (9.3) and i want to use case insensitive text in my database. For this Popstgres has a 'new' extension named 'citext'.
As i understand it, django can't use this extension out of the box, so i have made an custom field:
class RsCharField(models.CharField):
...
def db_type(self, connection):
return 'citext'
I use a CharField as baseclass, because i still want all the django perks of being able to set a maximum length and the validators that come with that.
The database is created correctly and i end up with citext-tables:
description | citext | not null
But when i do a query, django translates te query to:
SELECT * FROM .... WHERE mytable.description::text LIKE 'TEST%'
which still is case sensitive. When i do a manual select and drop the ::text it works case-insensitive.
Question: What am i doing wrong, and how can i make my CharFields behave like case-insensitive fields in django when doing queries?
note: most importantly i want my indexes to behave like case insensitive indexes.

use the classes provided in django.contrib.postgres.fields.citext
https://docs.djangoproject.com/pt-br/1.11/_modules/django/contrib/postgres/fields/citext/

Related

Django ORM case sensitive lookup returns case insensitive results

I have file field on a model and want to find instance by file path.
>>> path
u'docs/grinbeta_1.pdf'
>>> DocFileVersion.objects.filter(file=path).values_list('file', flat=True)
[u'docs/grinbeta_1.pdf', u'docs/Grinbeta_1.pdf']
I expect the query to return only the first result.
It's probably due to the collation setting you are using in DATABASE configuration. Take a look at django doc

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.

How to make case insensitive queries with Django Models

I have an member model with contains an email field. I recently realized that if a part of the email is capitalized, it won't show up in Django queries if I try to filter by the email (multiple member objects have the same email, but it may not be capitalized). I could have just made all emails lower-case when entering them into the database, but it's too late for that now (as the website is already launched). So how do I check who has a certain email, without being case sensitive?
Just use iexact:
User.objects.filter(email__iexact='email#email.com')
Case-insensitive exact match. If the value provided for comparison is None, it will be interpreted as an SQL NULL (see isnull for more details).
Member.objects.filter(email__iexact=email)

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 query: field is substring

In Django I have my Site model that contains the field "base_url" that's the base url of the site. I've an object like this:
foo = Site(base_url="http://foo_base_url.com/")
foo.save()
I receive an url and I want to obtain the site object having this url. I would like to perform a query in django like this:
Site.objects.get(base_url__is_substring="http://foo_base_url.com/something_non_base_url")
How can I perform this query?
Thanx
edit:
It doesn't exist a pattern for base_url, my foo site can be:
foo = Site(base_url="http://foo.com/base/url/")
What you want is not provided by the Django ORM but you can use the where param described under the reference for QuerySet:
url = "http://foo_base_url.com/something_non_base_url"
Site.objects.extra(where=["%s LIKE CONCAT('%%',field,'%%')"], params=[url]).get()
Keep in mind that there is no standard method of concatenation across DMBS so if you migrate, you'll have to migrate this code.
The only portable method would be to filter it using Python:
sites = [site for site in Site.objects.all() if site.base_url in url]
although this is of course not ideal for huge data sets.