Get all fields from DB where value contains number using Django - django

How to get all field from DB where value have number?
Example valid: 1test, tes1t, test1
I suppose something like this: field__contains

You can do this with a regex query.
Model.objects.filter(value__regex=r'\d')

Use icontains: django docs.
objs = Model.objects.filter(value__icontains="1")
The equivalent of doing an sql ILIKE "%1%" (case insensitive)
contains may work just as well actually if it's a number, that's a simple LIKE
Edit: To answer your comment yes you'd need to loop over the numbers. See this question

Related

Django istartswith and contains in same query?

I need to build a simple username search. I want to have it ordered by usernames that start with the query and then after usernames that contain the string.
if I have a list of usernames like this
john
matt
atom
atyler
mrmat
I want it to order like so:
atom
atyler
matt
mrmat
How would I achieve this in a single query? Right now I have
users = User.objects.filter(Q(name__istartswith='at') | Q(name__icontains='at'))
But this returns:
matt
mrmat
atyler
atom
class Z(Func):
function = 'ilike'
template = "%(expressions)s %(function)s 'in%%%%'"
for u in User.objects.filter(username__icontains('in'))\
.annotate(q=Z(F('username')))\
.order_by('-q', 'username'):
print u.username, u.q
ilike is a postgres extension, for mysql you'll have to either sacrifice case insensitivity or write the corresponding workaround for that.
The "old" way:
User.objects.filter(username__icontains='at')\
.extra(select={'q': "username ilike 'at%%%%'"},
order_by=['-q', 'username'])
This code block filters the queryset and orders it as required by OP.
Also the note about ilike from the second answer applies here.

In querying a collection in a Mongo database with Mongoose, how can I find where a value is LIKE a query term?

I've search hard for an answer to this but haven't found anything that works. I have a NodeJS app, with the Mongoose ORM. I'm trying to query my Mongo database where a result is LIKE the query.
I have tried using a new RegExp to find the results, but it hasn't worked for me. The only time I get a result is when the query is exactly the same as the collection property's value.
Here's what I'm using right now:
var query = "Some Query String.";
var q = new RegExp('^/.*'+ query +'.*/i$');
Quote.find({author: q}, function(err, doc){
cb(doc);
});
If the value of an author property contains something LIKE the query (for instance: 'some. query String'), I need to return the results. Perhaps stripping case, and excluding special characters is all I can do? What is the best way to do this? My RegEx in this example is obviously not working. Thanks!
You likely want to create your RegExp as follows instead as you don't include the / chars when using new RegExp:
var q = new RegExp(query, 'i');
I don't know of a way to ignore periods in the author properties of your docs with a RegExp though. You may want to look at $text queries for more flexible searching like that.

Django startswith on fields

let's say that I have an Address model with a postcode field. I can lookup addresses with postcode starting with "123" with this line:
Address.objects.filter(postcode__startswith="123")
Now, I need to do this search the "other way around". I have an Address model with a postcode_prefix field, and I need to retrieve all the addresses for which postcode_prefix is a prefix of a given code, like "12345". So if in my db I had 2 addresses with postcode_prefix = "123" and "234", only the first one would be returned.
Something like:
Address.objects.filter("12345".startswith(postcode_prefix))
The problem is that this doesn't work.
The only solution I can come up with is to perform a filter on the first char, like:
Address.objects.filter(postcode_prefix__startswith="12345"[0])
and then, when I get the results, make a list comprehension that filters them properly, like this:
results = [r for r in results if "12345".startswith(r.postcode_prefix)]
Is there a better way to do it in django?
Edit: This does not answer the original question but how to word a query the other way around.
I think what you are trying to do with your "something like" line is properly written as this:
Address.objects.filter(postcode__startswith=postcode_prefix)
In SQL terms, what you want to achieve reads like ('12345' is the postcode you are searching for):
SELECT *
FROM address
WHERE '12345' LIKE postcode_prefix||'%'
This is not really a standard query and I do not see any possibility to achieve this in Django using only get()/filter().
However, Django offers a way to provide additional SQL clauses with extra():
postcode = '12345'
Address.objects.extra(where=["%s LIKE postcode_prefix||'%%'"], params=[postcode])
Please see the Django documentation on extra() for further reference. Also note that the extra contains pure SQL, so you need to make sure that the clause is valid for your database.
Hope this works for you.
Bit of a mouthful but you can do this by annotating your search value and then filtering against it. All happens pretty quickly in-database.
from django.db.models import Value as V, F, CharField
Address.objects.exclude(
postcode_prefix=''
).annotate(
postcode=Value('12345', output_field=CharField())
).filter(
postcode__startswith=F('postcode_prefix')
)
The exclude is only necessary if postcode_prefix can be empty. This would result in an SQL like '%', which would match every postcode.
I'm sure you could do this via a nice templated function these days too... But this is clean enough for me.
A possible alternative. (Have no idea how it compares to the accepted solution with a column as the second param to like, in execution time)
q=reduce(lambda a,b:a|b, [Q(postcode__startswith=postcode[:i+1]) for i in range(len(postcode))])
Thus, you generate all prefixes, and or them together...
The raw SQL query that would do that you need looks something like this:
select * from postal_code_table where '1234567' like postal_code||'%'
This query will select any postal_code from your table that is a substring of '1234567' and also must start from begining, ie: '123', '1234', etc.
Now to implement this in Django, the preferred method is using a custom look up:
from django.db.models.fields import Field
from django.db.models import Lookup
#Field.register_lookup
class LowerStartswithContainedBy(Lookup):
'''Postgres LIKE query statement'''
lookup_name = 'istartswithcontainedby'
def as_sql(self, compiler, connection):
lhs, lhs_params = self.process_lhs(compiler, connection)
rhs, rhs_params = self.process_rhs(compiler, connection)
params = lhs_params + rhs_params
return f"LOWER({rhs}) LIKE LOWER({lhs}) || '%%'", params
Now you can write a django query such as the following:
PostCode.objects.filter(code__istartswithcontainedby='1234567')
Similarly, if you are just looking for substring and do not require the startswith condition, simply modify the return line of as_sql method to the following:
return f"LOWER({rhs}) LIKE '%%' || LOWER({lhs}) || '%%'", params
For more detailed explanation, see my git gist Django custom lookup
A. If not the issue https://code.djangoproject.com/ticket/13363,
you could do this:
queryset.extra(select={'myconst': "'this superstring is myconst value'"}).filter(myconst__contains=F('myfield'))
Maybe, they will fix an issue and it can work.
B. If not the issue 16731 (sorry not providing full url, not enough rep, see another ticket above) you could filter by fields that added with '.annotate', with creation of custom aggreation function, like here:
http://coder.cl/2011/09/custom-aggregates-on-django/
C. Last and successful. I have managed to do this using monkeypatching of the following:
django.db.models.sql.Query.query_terms
django.db.models.fields.Field.get_prep_lookup
django.db.models.fields.Field.get_db_prep_lookup
django.db.models.sql.where.WhereNode.make_atom
Just defined custom lookup '_starts', which has reverse logic of '_startswith'

Django: Is there a simple way to query "Model.field starts with a digit (0 to 9)"?

Hopefully simple Django question here. Short of using a long chain of Q objects OR'd together, is there an simple way to query something like:
item = Item.objects.filter(name__startswith='[a digit here]')
Thanks!
You can user regex to query:
item = Item.objects.filter(name__regex=r'^\d[\w\d _-]+')
You will need to adjust the regex depending on what you are querying.

Django Haystack: Range search on MultiValueField

I was wondering if it is possible to do a range search on a MultiValueField. I have a model that looks like the following:
Book
Title = 'Awesome Book'
Prices = [ Decimal('10.00'), Decimal('15.00'), Decimal('20.00') ]
I am indexing the prices field with a MultiValueField and I would like to be able to do the follow:
sqs = SearchQueryResult()
sqs.filter(prices__gt=Decimal('10.00'), prices__lt=Decimal('20.00'))
Is this possible or do I have to use something else to do a range search on multiple values?
Update:
I forgot to mention that the __gt doesn't work and I think it's because it's indexing it as a list of strings. I found the following link where they talk about subclassing MultiValueField. I tried this but I can't get it to give me a list of decimals. The subclassed MultiValueFiled looks like the following:
class MultiValueDecimalField(fields.MultiValueField):
field_type = 'decimal'
One way to solve this problem is doing the following:
sqs.filter(prices__in=['%.2f' % (x/100.00) for x in range(1000, 2000)])
It's very ugly but it works. Still open to other answer though.
Same thing: when I applied filters __gte, __gt etc. I noticed that SearchQuerySet returns incorrect data. When I changed field type to FloatField everything started working right. looks like bug, or smth
Have you tried the range field lookup?
SearchQuerySet().filter(view_count__range=[3, 5])
http://django-haystack.readthedocs.org/en/latest/searchqueryset_api.html#field-lookups