Searching in multiple models' tables in Django Rest Framework - python

I have 3 tables
PC(ID, PcNAME, Brand)
CellPhoness(ID, CellPhoneName, Brand)
Printers(ID, PrinterName, Brand).
There is no relationship between the 3 tables. I would like to run a query where the user can input the search string and the program will search the 3 models for where the data exists and return the same with the Id, name, and brand in the form of a JSON response.

You can do something like this:
Get query text from query params
Filter based on it
Return serializer data
def view(request):
query = request.GET.get("query", None)
pcs = PC.objects.all()
cell_phones = CellPhone.objects.all()
printers = Printer.objects.all()
if query:
pcs = pcs.filter(name__icontains=query)
cell_phones = cell_phones.filter(name__icontains=query)
printers = printers.filter(name__icontains=query)
return JsonResponse({"pcs": PCSerializer(instances=pcs, many=True).data,
"cell_phones": CellPhoneSerializer(instances=cell_phones, many=True).data,
"printers": PrinterSerializer(instances=printers, many=True).data})
You'll need to create serializers for each objects, please have a look at this documentation.

Related

Get column names where searched value was found in Django

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

django nested query or join two tables

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')

Django/PostgreSQL Full Text Search - Different search results when using SearchVector versus SearchVectorField on AWS RDS PostgreSQL

I'm trying to use the Django SearchVectorField to support full text search. However, I'm getting different search results when I use the SearchVectorField on my model vs. instantiating a SearchVector class in my view. The problem is isolated to an AWS RDS PostgreSQL instance. Both perform the same on my laptop.
Let me try to explain it with some code:
# models.py
class Tweet(models.Model):
def __str__(self):
return self.tweet_id
tweet_id = models.CharField(max_length=25, unique=True)
text = models.CharField(max_length=1000)
text_search_vector = SearchVectorField(null=True, editable=False)
class Meta:
indexes = [GinIndex(fields=['text_search_vector'])]
I've populated all rows with a search vector and have established a trigger on the database to keep the field up to date.
# views.py
query = SearchQuery('chance')
vector = SearchVector('text')
on_the_fly = Tweet.objects.annotate(
rank=SearchRank(vector, query)
).filter(
rank__gte=0.001
)
from_field = Tweet.objects.annotate(
rank=SearchRank(F('text_search_vector'), query)
).filter(
rank__gte=0.001
)
# len(on_the_fly) == 32
# len(from_field) == 0
The on_the_fly queryset, which uses a SearchVector instance, returns 32 results. The from_field queryset, which uses the SearchVectorField, returns 0 results.
The empty result prompted me to drop into the shell to debug. Here's some output from the command line in my python manage.py shell environment:
>>> qs = Tweet.objects.filter(
... tweet_id__in=[949763170863865857, 961432484620787712]
... ).annotate(
... vector=SearchVector('text')
... )
>>>
>>> for tweet in qs:
... print(f'Doc text: {tweet.text}')
... print(f'From db: {tweet.text_search_vector}')
... print(f'From qs: {tweet.vector}\n')
...
Doc text: #Espngreeny Run your 3rd and long play and compete for a chance on third down.
From db: '3rd':4 'chanc':12 'compet':9 'espngreeni':1 'long':6 'play':7 'run':2 'third':14
From qs: '3rd':4 'a':11 'and':5,8 'chance':12 'compete':9 'down':15 'espngreeny':1 'for':10 'long':6 'on':13 'play':7 'run':2 'third':14 'your':3
Doc text: No chance. It was me complaining about Girl Scout cookies. <url-removed-for-stack-overflow>
From db: '/aggcqwddbh':13 'chanc':2 'complain':6 'cooki':10 'girl':8 'scout':9 't.co':12 't.co/aggcqwddbh':11
From qs: '/aggcqwddbh':13 'about':7 'chance':2 'complaining':6 'cookies':10 'girl':8 'it':3 'me':5 'no':1 'scout':9 't.co':12 't.co/aggcqwddbh':11 'was':4
You can see that the search vector looks very different when comparing the value from the database to the value that's generated via Django.
Does anyone have any ideas as to why this would happen? Thanks!
SearchQuery translates the terms the user provides into a search query object that the database compares to a search vector. By default, all the words the user provides are passed through the Stemming algorithms , and then it looks for matches for all of the resulting terms.
there two issue need to be solved first gave stemming algorithm information about language.
query = SearchQuery('chance' , config="english")
and second is replace this line
rank=SearchRank(F('text_search_vector'), query)
with
rank=SearchRank('text_search_vector', query)
about the missing word in text_search_vector this is standard procedure of Stemming algorithms to remove common word known as stop word

Include a table list view in details view

With flask_sqlalchemy, I have two tables (A & B) joined together by an association proxy table (C), in which there are some extras fields.
For now with flask_admin I have a ModelView on C, and in this list view I have appended (with the column_formatters option) a link on each item in the related A table column to its details_view page.
It works fine, but I don't know, in this details-view page, how to append a filtered table, based on C, with just the rows relevant to the selected A item.
Ok, I answer to myself here if someone needs it.
I do the opposite by creating another list_view, but for the selected record I want by modifying the index_view method and passing extras params (details) to the template:
class TableCView(admin.ModelView):
list_template = 'modified_listview.html'
#expose('/')
def index_view(self):
self.a_id = request.args.get('id', None)
self._template_args['a_id'] = self.a_id # add more params here
return super(TableCView, self).index_view()
def get_query(self):
# Filter records by a_id
query = super(TableCView, self).get_query()
if self.a_id:
query = query.filter(self.model.a_id == self.a_id)
return query
def get_count_query(self):
query = super(TableCView, self).get_count_query()
if self.a_id:
query = query.filter(self.model.a_id == self.a_id)
return query

Django concatenate list queries from two models

As a Django newbie, I am trying to return JSON Objects from two models with each object containing the username, id, ticketID. Right now the code is simply putting the lists together without indexing. I should point out that there is a relationship between user and ticket so that can be traversed also.
{"username":"Paul","id":2}, {"username":"Paul","id":2}, {"username":"Ron","id":19}, {"id":"1c6f039c"}, {"id":"6480e439"},
{"id":"a97cf1s"}
class UsersforEvent(APIView):
def post(self, request):
body_unicode = request.body.decode('utf-8')
body = json.loads(body_unicode)
value = body['event']
queryset = Ticket.objects.filter(event = value)
referenced_users = User.objects.filter(ticket_owner__in=queryset.values('id'))
result_list = list(itertools.chain(referenced_users.values('username', 'id'), queryset.values('id')))
return Response((result_list))
You should do a single query to get the ticket with the related user for each one, then create the list of dicts from there. Assuming your Ticket model has an "owner" field which is a FK to User:
queryset = Ticket.objects.filter(event=value).select_related('owner')
result_list = [{'ticket_id': ticket.id, 'username': ticket.owner.username, 'user_id': ticket.owner.id}
for ticket in queryset]
(Note, this shouldn't be the action of a POST though; that is for changing data in the db, not querying.)

Categories

Resources