Django: Select object contains all keywords - python

Here is the db looks like:
id | Post | tag
1 | Post(1) | 'a'
2 | Post(1) | 'b'
3 | Post(2) | 'a'
4 | Post(3) | 'b'
And here is the code of the module
class PostMention(models.Model):
tag = models.CharField(max_length=200)
post = models.ForeignKey(Post,on_delete=models.CASCADE)
Here is the code of search,
def findPostTag(tag):
keywords=tag.split(' ')
keyQs = [Q(tag=x) for x in keywords]
keyQ = keyQs.pop()
for i in keyQs:
keyQ &= i
a = PostMention.objects.filter(keyQ).order_by('-id')
if not a:
a=[]
return a
(this code does not work correctly)
I withdraw the tags and save each as one row in the database. Now I want to make a search function that the user can input more than one keywords at the same time, like 'a b', and it will return 'Post(1)'. I searched for some similar situations, but seems all about searching for multi keywords in one row at the same time, like using Q(tag='a') & Q(tag='b'), it will search for the tag that equals to both 'a' and 'b'(in my view), which is not what I want (and get no result, obviously). So is there any solution to solve this? Thanks.

Is this cases, django provides, ManyToManyField, to work correctly you must to use:
class Tags(models.Model):
tag = models.CharField(unique=True, verbose_name='Tags')
class Post(models.Model): #your model
title = models.CharField(verbosone_name = 'Title')
post_tags = models.ManyToManyField(Tags, verbose_name='Choice your tags')
So you'll choice many tags to your post

Related

creates a binary or combination of all attributes

I want to create a query that creates a binary or combination of attributes.
For example, I have the following class
class foo(models.Model):
m_person= models.ForeignKey('Person', on_delete=models.CASCADE)
m_rang = models.ForeignKey('Rang', on_delete=models.CASCADE)
m_a = models.BooleanField(default=True, name='a')
m_b = models.BooleanField(default=False, name='b')
m_c = models.BooleanField(default=False, name='c')
m_d = models.BooleanField(default=False, name='d')
...
I am currently reading this class as follows:
obj = foo.objects.all().first()
attributes = [i for i in dir(obj) if i.startswith('m_')]
for tag in attributes:
if hasattr(foo, tag.__name__):
t = foo.objects.filter(person_id=aperson.pk, rang=arang).values_list(tag.__name__, flat=True)
if True in t:
do somthing
So I run through all the instances that match the person and the rank to then check the attribute.
I bet it's somehow more intelligent in combination.
I would actually like to read a combined "or" class from the database in order to process it further. instead of questioning each attribute individually...
since I need a or link, you could use first(value = true) somehow.
my wish would be something like this:
f = foo.objects.filter(person_id=aperson.pk, rang=arang).OR()
where the attributes then combine into something like this:
f.m_a = foo[0].m_a | foo[1].m_a | foo[2].m_a...
f.m_b = foo[0].m_b | foo[1].m_b | foo[2].m_b...
f.m_c = foo[0].m_c | foo[1].m_c | foo[2].m_c...
f.m_d = foo[0].m_d | foo[1].m_d | foo[2].m_d...
...
with:
foo[0] & foo[1] & foo[2] & ... element from person_id=aperson.pk and rang=arang

Django queryset with bidirectional relations

I'm struggling with making an efficient queryset with the following model:
class Connection(models.Model):
from = models.ForeignKey(User, related_name='from_connections')
to = models.ForeignKey(User, related_name='to_connections')
status = models.SmallIntegerField()
What I'm trying to do is, for a specified user, fetch a list of all his connections (so where he is either from or to) and annotate the status where he is from but also annotate the reverse status where he is to.
So for the example:
from | to | status
------------------------
A | B | 1
B | A | 0
C | A | 2
A | D | 2
the results would be something like this:
user | status | reverse_status
-----------------------------------
B | 1 | 0
C | None | 2
D | 2 | None
The closest solution I've got to so far is something like this:
qs = Connection.objects.filter(from_id=a_id)
reverse_qs = Connection.objects.filter(from_id=OuterRef("to_id"), to_id=a_id)
qs = qs.annotate(reverse_status=Subquery(reverse_status.values("status")[:1]))
This almost gives me what I need but since the queryset is including only results where user A is from, the results obviously don't contain anything for user C (from the example table above).
I also tried exploring the route with using related_names like
User.objects.filter(Q(from_connections__to=a_id)|Q(to_connections__from=a_id).annotate...
but this approach didn't get me far.
Does anyone have any ideas how to solve this using Django ORM? Much appreciated.
When you create a model having 2 ForeignKeys, you have to specify a related_name, Example :
class Connection(models.Model):
from = models.ForeignKey(User, related_name = 'from_connection')
to = models.ForeignKey(User, related_name = 'to_connection')
status = models.SmallIntegerField()
That will help in backwards relationships, more details in the docs

a search box with options relevant for a particular item that is selected django

Am having a search box, that i can use to search for items in django database and prints the results out at the template as a table.
Presently the code is working but i intend customizing the search, to accommodate a select tag so that whatever the user typed and and selected should query the database and fetch the outcome or result.
i tried but it not working
q is gotten from text input while x is gotten from select tag
here is my code:
def search_form(request):
data = OrderItem.objects.order_by().values_list('certification_type', flat=True).distinct()
print data
if 'q' in request.GET and request.GET['q']:
q = request.GET['q']
print q
x = request.GET['certification_type']
print x
items = OrderItem.objects.filter(Q(order_type__iexact=x and order_type__iexact=q) | Q(certification_type__iexact=x and certification_type__iexact=q) | Q(item__iexact=x and item__iexact=q)
| Q(certification_no__iexact=x and certification_no__iexact=q) | Q(client__user__email__iexact=x and client__user__email__iexact=q) | Q(client__phone_number__iexact=x and client__phone_number__iexact=q)
| Q(created_on__icontains=x and created_on__icontains=q))
for x in items:
for q in items:
print items
return render(request, 'i/search_results.html', {'items':items, 'q_query':q, 'x_query':x})
else:
return render(request, 'i/search_form.html', {'error':True, "data":data})
I think you are misunderstanding how lookups with Q objects work.
Assuming you want to filter OrderItem objects by
occurrence of the search string q in any attribute
certification_type gotten from the select tag x
you could do the following:
items = OrderItem.objects.filter(
certification_type=x,
Q(order_type__iexact=q) |
Q(item__iexact=q) |
Q(certification_no__iexact=q) |
Q(client__user__email__iexact=q) |
Q(client__phone_number__iexact=q) |
Q(created_on__icontains=q)
)

How to write a query with many ANDs and ORs with sum in Python?

I'm trying to write the following query in Django/Python:
in this query, I don't have a simple or, but I have many ands also and a sum
SELECT sum(value) FROM myapp_category
WHERE (name='difficulty' AND key='hard')
OR (name= 'success' AND key='yes')
OR (name= 'alternative' AND key='yes')
OR (name= 'processing' AND key='good')
OR (name= 'personal_touch' AND key='yes') `
and here's my model:
class Category(models.Model):
name = models.CharField(max_length=50)
key = models.CharField(max_length=30)
value = models.FloatField(blank=True, default=0)
def __str__(self):
return self.name.encode('utf_8') + "_" + self.key.encode('utf_8')
and I don't want to use the raw sql, so what can I use for this ?
Update Answer:
Thanks for your answers, this is the complete answer:
sum = Category.objects.filter(Q(name='difficulty',key=evaluation.difficulty) |
Q(name='nogos',key=evaluation.nogos) |
Q(name='success',key=evaluation.success) |
Q(name='alternative',key=evaluation.alternative) |
Q(name='processing',key=evaluation.processing) |
Q(name='personal_touch',key=evaluation.personal_touch))
.aggregate(result=Sum('value'))
score = float(sum['result'])
Try this;
from django.db.models import Q, Sum
Category.objects.filter(Q(name='difficulty',key='hard') | Q(name='success',key='yes') | Q(name='alternative',key='yes') | Q(name='processing',key='good') | Q(name='personal_touch',key='yes')).aggregate(Sum('value'))
UPD
from django.db.models import Q
results = Category.objects.filter(
Q(name="difficulty", key="hard") | Q(name= "success", key="yes") |
Q(name="alternative", key="yes")|Q(name="processing" AND key="good") |
Q(name="personal_touch",key="yes"))
Not really a solution but maybe input for other ideas:
SELECT sum(value) FROM myapp_category
WHERE name+"/"+key IN (
'difficulty/hard',
'success/yes',
'alternative/yes',
'processing/good',
'personal_touch/yes'
)
Problems:
Also lists cannot be provided using parameters
The query is slower because indexes cannot be used

How can I make a query by a Django foreignkey description?

if i have this code
class Father(models.Model):
Description = models.CharField(max_length=50)
Code = models.IntegerField(max_length=2, unique=True)
def __unicode__(self):
return "%s (%s)" % (self.Description, self.Code)
class Son(models.Model):
Father = models.ForeignKey(Father)
Description = models.CharField(max_length=50)
And I want to create a filter by the select box shown to the user.
Assuming that I have a record in Father like:
# | Description | Code
--------------------------
1 | Fred Nichols | 100
In the ForeignKey field should have a HTML content like:
<option value="1">Fred NIchols (100)</option>
if I try to query by the field in the son model:
Son.objects.filter(Father__Contains="Fred")
I get an error. In the documentation of Django the nearest option should be something like:
Son.objects.filter(Father__Description__contains="Fred")
or for any of the columns data
Son.objects.filter(Q(Father__Description__contains="Fred") | Q(Father__Code__Contains="Fred") )
I'd like to make something the most similar to the user info shown.
How could I make a query that could do that?
In single step u could do this :
Son.objects.filter(father__Description__contains="Fred")
you were doing it right the only thing that was wrong is :
the referencing entity Father should be lowercase name of the model
reference

Categories

Resources