Related
I have a function that takes a user's input from a list of data and searches my database for any items that matches the user's input, and returns all results that are in my database:
results = results.filter(
reduce(or_, (Q(name__icontains=itm.strip()) for itm in query))
)
I would like to handle cases where the user's input is not present in my database. since results fitlers down to what exists, how can I check if the above code failed to find at least one matching result for a query, and store that query in a variable? For example, if results queried my database for the following list: ['one', 'two', 'thee'], assuming 'thee' is not in my database but the other two are, I would like to store the string "thee" in a variable to use later
You can simply evaluate results as a Boolean:
if not results:
print('No match found.')
From QuerySet's documentation:
bool(). Testing a QuerySet in a boolean context, such as using bool(),
or, and or an if statement, will cause the query to be executed. If
there is at least one result, the QuerySet is True, otherwise False.
For example:
if Entry.objects.filter(headline="Test"):
print("There is at least one Entry with the headline Test")
You can add one query for query:
For example:
query = query.append(Q(name__isnull=True)) or something that always False
Instead of trying to do it one piece of code:
results = results.filter(
reduce(or_, (Q(name__icontains=itm.strip()) for itm in query))
)
I iterated over each item in query and checked if it exists
for each in query:
r = results.filter(name__icontains=each)
if r.exists() == False:
Do something with each
Though not as efficient as I'd like, it solves the problem for now
I have
class holiday(models.Model):
h_date=models.DateField()
h_description=models.CharField(max_length=200)
when I query
h_list=holiday.objects.all().values('h_date')
I get output as
<QuerySet[{'h_date':datetime.date(2017,5,1)},{'h_date':datetime.date(2017,4,2)}]>
But I need output as
2017-05-01
2017-04-02
How can I get that output with just querying the database?
values() method returns a QuerySet object. (BTW, you could use dates, which directly evaluates to a list of datetime.date objects). You could use list comprehension to apply format though strftime method to each item:
[d.strftime('%Y-%m-%d') for d in holiday.objects.all().dates('h_date', 'day')]
I am trying to select a table where a certain value is not present in a reference field. Is it possible to negate the contains() method?
grid = SQLFORM.smartgrid(db.redaktion.projekt.contains(projektid)
The negation operator in pyDAL queries is ~. Also, the first argument of smartgrid must be a Table rather than a Query. To apply a query to a given table, use the constraints argument. So, it would be:
grid = SQLFORM.smartgrid(db.redaktion,
constraints={'redaktion': ~db.redaktion.projekt.contains(projektid)})
See http://web2py.com/books/default/chapter/29/06/the-database-abstraction-layer#Logical-operators.
I have one scenario, in which I am searching a no pan string in a documents. In my application, we are sending two query request to SOLR i.e one is with Exact query(i.e phrase query) which returns me Exact results and next query is AND query. But it happens that the results of Exact query are also contains in the AND query, so I want to remove that records from AND query results. So its possible to remove from SOLR end?
I am using sunspot gem and rails.
If your document contains any unique field then use that field in second query as a not in query.
for example if you have id as unique field.
Then from the first query you get those ids
and put in the second query as
-id:(123 OR 345)
So from the second queries result these will get filtered...
Or simply you can re-formulate the second request to include AND but exclude the exact matches.
The updated second request becomes a negation of the current first request (exclude exact matches) combined with your current second request (via an and operation).
I have a Result object that is tagged with "one" and "two". When I try to query for objects tagged "one" and "two", I get nothing back:
q = Result.objects.filter(Q(tags__name="one") & Q(tags__name="two"))
print len(q)
# prints zero, was expecting 1
Why does it not work with Q? How can I make it work?
The way django-taggit implements tagging is essentially through a ManytoMany relationship. In such cases there is a separate table in the database that holds these relations. It is usually called a "through" or intermediate model as it connects the two models. In the case of django-taggit this is called TaggedItem. So you have the Result model which is your model and you have two models Tag and TaggedItem provided by django-taggit.
When you make a query such as Result.objects.filter(Q(tags__name="one")) it translates to looking up rows in the Result table that have a corresponding row in the TaggedItem table that has a corresponding row in the Tag table that has the name="one".
Trying to match for two tag names would translate to looking up up rows in the Result table that have a corresponding row in the TaggedItem table that has a corresponding row in the Tag table that has both name="one" AND name="two". You obviously never have that as you only have one value in a row, it's either "one" or "two".
These details are hidden away from you in the django-taggit implementation, but this is what happens whenever you have a ManytoMany relationship between objects.
To resolve this you can:
Option 1
Query tag after tag evaluating the results each time, as it is suggested in the answers from others. This might be okay for two tags, but will not be good when you need to look for objects that have 10 tags set on them. Here would be one way to do this that would result in two queries and get you the result:
# get the IDs of the Result objects tagged with "one"
query_1 = Result.objects.filter(tags__name="one").values('id')
# use this in a second query to filter the ID and look for the second tag.
results = Result.objects.filter(pk__in=query_1, tags__name="two")
You could achieve this with a single query so you only have one trip from the app to the database, which would look like this:
# create django subquery - this is not evaluated, but used to construct the final query
subquery = Result.objects.filter(pk=OuterRef('pk'), tags__name="one").values('id')
# perform a combined query using a subquery against the database
results = Result.objects.filter(Exists(subquery), tags__name="two")
This would only make one trip to the database. (Note: filtering on sub-queries requires django 3.0).
But you are still limited to two tags. If you need to check for 10 tags or more, the above is not really workable...
Option 2
Query the relationship table instead directly and aggregate the results in a way that give you the object IDs.
# django-taggit uses Content Types so we need to pick up the content type from cache
result_content_type = ContentType.objects.get_for_model(Result)
tag_names = ["one", "two"]
tagged_results = (
TaggedItem.objects.filter(tag__name__in=tag_names, content_type=result_content_type)
.values('object_id')
.annotate(occurence=Count('object_id'))
.filter(occurence=len(tag_names))
.values_list('object_id', flat=True)
)
TaggedItem is the hidden table in the django-taggit implementation that contains the relationships. The above will query that table and aggregate all the rows that refer either to the "one" or "two" tags, group the results by the ID of the objects and then pick those where the object ID had the number of tags you are looking for.
This is a single query and at the end gets you the IDs of all the objects that have been tagged with both tags. It is also the exact same query regardless if you need 2 tags or 200.
Please review this and let me know if anything needs clarification.
first of all, this three are same:
Result.objects.filter(tags__name="one", tags__name="two")
Result.objects.filter(Q(tags__name="one") & Q(tags__name="two"))
Result.objects.filter(tags__name_in=["one"]).filter(tags__name_in=["two"])
i think the name field is CharField and no record could be equal to "one" and "two" at same time.
in python code the query looks like this(always false, and why you are geting no result):
from random import choice
name = choice(["abtin", "shino"])
if name == "abtin" and name == "shino":
we use Q object for implement OR or complex queries
Into the example that works you do an end on two python objects (query sets). That gets applied to any record not necessarily to the same record that has one AND two as tag.
ps: Why do you use the in filter ?
q = Result.objects.filter(tags_name_in=["one"]).filter(tags_name_in=["two"])
add .distinct() to remove duplicates if expecting more than one unique object