I have this query:
search = request.GET['q']
Entries = Entry.objects.filter(Q(field1__icontains=search), Q(field2__icontains=search), Q(field3__icontains=search))
Is there an elegant way to make this cleaner? (I mean make somthing generic like Q(var_field__icontains=search) and the var_field will be retrived from a requested post that is one of these values field1, field2, field3).
So, is this working for you?
search = request.GET['q']
fieldnames = ('field1', 'field2', 'field3')
filters = reduce(operator.and_,
(Q(**{'{}__icontains'.format(fieldname): search})
for fieldname in fieldnames))
Entries = Entry.objects.filter(filters)
Related
I'm performing a query in a function inside the views.py as follows:
input_dict = {'id': 'id',
'table': 'my_table',
'first_col': 'my_first_col',
'first_name': 'my_first_name'}
query = '''
SELECT %(id)s
FROM %(table)s
WHERE %(first_col)s = %(first_name)s '''
qs = my_model.objects.raw(query, input_dict)
print(qs)
which prints:
qs: <RawQuerySet:
SELECT id
FROM my_table
WHERE my_first_col = my_first_name >
However, when I try to run this line:
ids = [item.id for item in qs]
it gives me an error:
psycopg2.errors.SyntaxError: syntax error at or near "'my_table'"
LINE 3: FROM 'my_table'
and also:
django.db.utils.ProgrammingError: syntax error at or near "'my_table'"
LINE 3: FROM 'my_table'
What should I do?
django are not able to excecut your query.
I believe what you trying to acheive via the raw function it is not possible.
read the docs https://docs.djangoproject.com/en/3.0/topics/db/sql/ for better understanding how the function work
your dynamic options are realted either to the table fields and the where params:
the select fields
you can map fields in the query to model fields using the translations
argument to raw()
like :
name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'}
Person.objects.raw('SELECT * FROM some_other_table', translations=name_map)
the where params
If you need to perform parameterized queries, you can use the params
argument to raw()
lname = 'Doe'
Person.objects.raw('SELECT * FROM myapp_person WHERE last_name = %s', [lname])
at the end of the day, this will work, although it's not recomended unless you know exactly what you are doing as it might expose your system to sql attacks
query = '''
SELECT %(id)s
FROM %(table)s
WHERE %(first_col)s = %(first_name)s '''
query = query%input_dict
qs = my_model.objects.raw(query)
I'm searching Postgres as follows:
search_term = self.request.GET.get('search')
queryset = Package.objects.filter(package_description__search=search_term)
How do I make this return all objects if search_term is None or an empty string?
I've tried setting search_term to None or an empty string.
Django execute query only at moment when you try to get items of the query. So you can simple add if and combine your query
search_term = self.request.GET.get('search')
queryset = Package.objects.all()
if search_term:
queryset = queryset.filter(package_description__search=search_term)
link to the doc querysets-are-lazy thank #bdoubleu
I have the following case. I have a form with 3 fields which are submitted with POST method. Then the fields are captured and a search using Q is made on the database:
query = Model.objects.filter( Q(field1=field1) & Q(field2=field2) & Q(field3=field3))
The problem is that I would like to dynamically use the fields that are filled not the empty ones. That means that the query will contain one or two or three criteria depending on the user.
I have managed to perform the search I describe with nested if but considering adding extra fields it gets bigger and bigger.
thanks
You can write generic function to generate a query based on fields passed-in.
def generate_query(**kwargs):
query = Q()
for database_field, value in kwargs.items():
query_dict = {database_field:value}
if value:
query &= Q(**query_dict)
return query
And use it:
data = {"name":"john", "age__gte":25} # your post data
query = generate_query(**data)
objects = SomeModel.objects.filter(query)
# generally: SomeModel.objects.filter(request.POST)
Consider you have query field like below:
field = {'field1': 'value1', 'field2': 'value2', 'field3': None}
You can filter to remove null field as below:
non_empty_field = dict(filter(lambda x: x[1], field.items())) # output: {'field1': 'value1', 'field2': 'value2'}
For performing and query you can write
Model.objects.filter(**non_empty_field) # equivalent to Model.objects.filter(field1='value1', field2='value2')
to perform and query you don't need Q() object
For performing or query you can write:
Model.objects.filter(eval('|'.join(['(Q({}="{}"))'.format(i,j) for i,j in non_empty_field.items()])))
according to current field example above query will be equivalent to:
Model.objects.filter(Q(field1=value1) | Q(field2=value2))
I'm trying to order a queryset by the CharField 'name', but I want to exclude the 'Other' entry and add it as a last option for the user to choose...
self.fields["acquisition"].queryset = AcquisitionChannel.objects.exclude(name = "Other").order_by('name')
The above is obviously not good because it excludes the 'Other'...
Could it be done in Django? or I must use Javascript?
Thanks!
To manually add objects to a QuerySet, try _result_cache:
other = AcquisitionChannel.objects.get(name="Other")
objs = AcquisitionChannel.objects.exclude(name="Other").order_by("name")
len(objs) #hit the db to evaluate the queryset.
objs = objs._result_cache.append(other)
self.fields["acquisition"].queryset = objs
Quick and simple: add an order column that takes a special value using extra():
self.fields["acquisition"].queryset = (
AcquisitionChannel.objects
.extra(select={'order': '(CASE name WHEN %s THEN 1 ELSE 0 END)'},
select_params=['Other'],
order_by=['order', 'name']))
Using params, this method works on any DB (that supports CASE).
It's something like:
def get_choices():
choices = AcquisitionChannel.objects.exclude(name = "Other").order_by('name').values_list('value_column', 'text_column')
other = AcquisitionChannel.objects.filter(name = "Other").values_list('value_column', 'text_column')
choices = list(choices)
other = list(other)
return choices + other
then:
acquisition = forms.ChoiceField(choices=get_choices())
I'm trying to improve the performance of this code:
orderitems = OrderItem.objects.filter(order__contact=contact)
for orderitem in orderitems:
try:
pv = ProductVariation.objects.get(product=orderitem.product)
if pv.parent_id == parent_product.id:
return True
except:
pass
Essentially I want to get rid of the 'for' loop because its slow. I would like to do it using a single queryset if possible, but I just can't get my head around the syntax. Here is the SQL that I effectively want to reproduce. It creates a list which is fairly short so I can iterate through that looking for a match:
SELECT parent_id
FROM configurable_productvariation
WHERE product_id IN (
SELECT product_id
FROM shop_orderitem
WHERE order_id
IN (
SELECT id
FROM shop_order
WHERE contact_id = 4));
The '4' is the 'contact' referred to in the first line of python.
Many thanks,
Thomas
This should generate sql like yours
product_ids = OrderItem.objects.filter(order__contact=contact).values_list('product_id', flat=True)
ProductVariation.objects.filter(product_id__in=product_ids)