I have query that performs full text search on several columns (including on columns of models related using FK) in Django:
from django.contrib.postgres.search import SearchVector, SearchQuery, SearchRank
class TaskManager(models.Manager):
def search_by_text(self, text: str):
search_vector = SearchVector(
"task_type__name",
"order__registration_number",
"order__report_number",
"car_owner_name",
"task_number",
"order__customer_order_number",
"order__customer_owner",
"order__report_type__value",
)
search_query = SearchQuery(text)
return self.get_queryset().annotate(
rank=SearchRank(search_vector, search_query)
).order_by("rank")
How can I get not only found records but also column names where searched value was found for each record? Example:
>>> Entry.objects.search_by_text("some value")[0].columns_matched
["task_type__name", "task_number"]
I'm using Postgresql 10.12 and Django 2.2.10.
Solved this problem by creating migration which creates database view which has search_q column containing concatenated string with values from all searched columns.
CREATE VIEW app_taskdata_search_view
AS
SELECT Row_number()
over(
ORDER BY TASK.task_number) AS id,
Concat(tasktype.name, '|', TASK.description, '|', USER.first_name, '|',
USER.last_name) AS search_q
FROM app_taskdata AS TASK
inner join app_tasktype AS tasktype
ON TASK.task_type_id = tasktype.id
inner join users_user AS USER
ON TASK.user_id = USER.id
ORDER BY TASK.task_number;
Then in models.py:
class TaskDataSearchView(models.Model):
"""
Database view refrenced from.
"""
id = models.BigIntegerField(primary_key=True)
search_q = models.TextField()
class Meta:
db_table= "app_taskdata_search_view"
managed = False
Assuming I know the order of concatenated column values I can make a Python code which loops through result and checks if searched value was found in column:
text = "Some text to search"
records = TaskDataSearchView.objects.filter(search_q__icontains=text)
values = records[0].search_q.split("|")
# check if task_type column contains searched text
if text in values[0]:
field_mapping['task_type'] = True
P.S: Useful link
Related
It might be not new to all and need your expert guidance. I am trying to filter a column on a django-table2. Note I have not used django-filter here.
class Group(models.Model):
title = models.CharField(blank=True)
class Control(models.Model):
published = models.charField(auto_now=False)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
Now I am trying to filter in views.py as below
table = ControlTable(Control.objects.all().order_by('-published').filter(
group__in=form['contact'].value(),
)
Issue is this is working fine, but when selecting '-----' from dropdown then its showing blank table instead of all the values.
Again if I change the query filter as below
table = ControlTable(Control.objects.all().order_by('-published').filter(
Group__title__iexact=form['contact'].value(),
)
then throwing error Cannot resolve keyword 'Group' into field.
Could you please guide me on this?
That makes sense, if you select ----, then it uses None, so you are filtering for None. You should check for that:
items = ControlTable(Control.objects.all().order_by('-published')
group = form['contact'].value()
if group:
items = items.filter(
group__in=group
)
table = items
I list the debts of my customers from the "debts" table with the following code.
However, I would like to see the name and surname of the customer with the same ID number from the "Customer" table.
I get the person I specified with the following code but; I cannot print to "Debts.objects.values (" customer ")".
Is there an easy way to do this?
Thanks for your help.
class CustomerDetailDebtListAPIView(ListAPIView):
serializer_class = DebtCreateSerializer
def get(self, request):
# get customer , customerKey
obj_customer = Customer.objects.get(customer=85)
field_object_customer = Customer._meta.get_field('customer')
# field_value_customer = getattr(obj_customer, field_object_customer.attname)
print(obj_customer)
result = Debt.objects.values('customer') \
.annotate(totalDebt=Sum('totalDebt'), receivedAmount=Sum('receivedAmount')) \
.order_by('customer')
return Response(result)
I am supposing that customer is a foreign key. You can access fields of your related tables using __ operators. This is shown in below code
Debt.objects.all().annotate(totalDebt=Sum('totalDebt'), receivedAmount=Sum('receivedAmount')).order_by('customer').values('customer__surname')
or
from django.db.models import F
Debt.objects.all().annotate(totalDebt=Sum('totalDebt'), receivedAmount=Sum('receivedAmount'), surname=F('customer__surname')).order_by('customer').values('surname')
I have few form fields on search page. After performing the search, my page should display a list of possible matching results. If the user typed in only part of a title, ISBN, or author name, search page should find matches for those as well. Also if user typed only one or few field - page should show all matches.
Idk how to write query. If i have one value from request.form and other values is None - so whole query is empty
#app.route('/search', methods=("GET", "POST"))
def search_book():
books = None
if request.method == "POST":
isbn = request.form['isbn']
title = request.form['title']
author = request.form['author']
year = request.form['year']
books = db.query(Books).filter_by(isbn=isbn, title=title, author=author, year=year).all()
return render_template("search.html", books=books)
.filter_by(multiple arguments) will default to AND, meaning the user will have to enter data that matches all fields
This also means that if the user leaves fields empty, the query will only return books that have (for example) title = " " (when title form is empty), despite having entered a valid year.
This is probably not intended, from a user point of view. A way to fix this is to (1. validate input data, and then) add filters to a list if they are not empty, then add the non-empty fields using or_(*filter_list). Query will then return all rows that match any field specified by the forms.
from sqlalchemy import or_
query = db.query(Books)
filter_list = []
if request.form['isbn']:
filter_list.append(Book.isbn.ilike(request.form['isbn']))
if request.form['author']:
filter_list.append(Book.author.ilike(request.form['author']))
# etc...
if len(filter_list) > 0:
query = query.filter(or_(*filter_list))
didnt test code but *filter_list allows you to pass a list to the filter method, or_ allows you to change the default AND to OR
more here:
Using OR in SQLAlchemy
Use the 'or_()' method . This will search all the matching results for any given column
name = request.form.get('res')
result = Books.query.filter(db.or_(Books.author==name , Books.isbn==name , Books.title==name)).all()
'res' is the search entry given by the user in the search form in your html page , as mentioned it can be anything ISBN , title or the author's name
Most examples are in the form of finding A in data A to Z.
A DB table does not have a single field from A to Z. When a DB table has several fields together, I want to know the field I'm looking for as a field value and I want to figure out another value with that field value.
For example, searching for a specific name in a DB that contains information from all the students will determine the age.
from Python, Django DB
My data consists of 3 rows:
{title:'1', price:'20'}
{title:'2', price:'30'}
{title:'1', price:'10'}
I want to find title '1' and then return price fileds
Expexted Output:
{title:'1', price:'20'}
{title:'1', price:'10'}
Views.py:
#csrf_exempt
def searching(request):
if request.method == "POST":
parameter = request.POST.get('title')
searchResult = NaverData.objects.filter(Q(title__icontains=parameter)).distinct()
ouput = searchResult
return HttpResponse(ouput)
else:
#GET request
return HttpResponse('GET REQUEST')
Try below code:
searchResult = NaverData.objects.all().filter(title=parameter)
check this
searchresult= NaverData.objects.values("prize").filter(title__exact=parameter)
I am working on a listing in django project. The scenario is that When i click on FAQ listing page then it redirects me to the listings where i get all faq. Now i have to search using different keywords. There is total five keywords through which i can search for particular results. Code is
questions = Help.objects.all().filter().values('id','question','description','status','created','modified').order_by('-id')
if 'question' in ajax_data:
#add filter for question
if 'description' in ajax_data:
#add filter for description
if 'status' in ajax_data:
#add filter for status
if 'created' in ajax_data:
#add filter for created
if 'modified' in ajax_data:
#add filter for modified
questions = Help.objects.all().filter(#add all conditions here dynamically after applying filters).values('id','question','description','status','created','modified').order_by('-id')
First when page refresh it executes first query which returns all data, now using ajax filters have to be applied, i have done all ajax code just want logic of this search. Search should perform like if i enter question only it should filter according to question, but if i search using question, status and created filed it should apply filter for all these three keywords.
questions = Help.objects.all()
filters = {}
if 'question' in ajax_data:
filters['question'] = ajax_data.get('question')
if 'description' in ajax_data:
filters['description'] = ajax_data.get('description')
if 'status' in ajax_data:
filters['status'] = ajax_data.get('status')
if 'created' in ajax_data:
filters['created'] = ajax_data.get('created')
if 'modified' in ajax_data:
filters['modified'] = ajax_data.get('modified')
questions = questions.filter(**filters).values('id','question','description','status','created','modified').order_by('-id')
Check this link https://docs.python.org/3/glossary.html#term-argument
You can use request.GET.get('filter_name')
e.g if you have a filter by title:
query = Model.objects.all()
title = request.GET.get('title')
if title:
query = query.filter(title__icontains=title)
...and so on
note that your url should contain get parameters like http://myurl.com/?title=abc
EDIT
for one query filter you can use Q object from django.db.models
filter = Q()
if title:
filter &= Q(title__icontains=title)
if category:
filter &= Q(category__icontains=category)
query = query.filter(filter)