I have a Django application with a Publication model and a Tag model. Each publication has one or more Tags associated with it. I want to query the database with a set of two Tags and have returned only publications that have BOTH of those tags.
I cannot seem to find the syntax for this although I am certain it is readily available - I suppose I am not using the correct language to search. What I have tried already is:
pubs_for_tags = Publication.objects.filter(tags__title__istartswith=q, tags__title__istartswith=q2)
But this gives me an error "keyword argument repeated". I've also tried some variations of this, but nothing has worked so far. Can someone enlighten me on the correct syntax for this?
pubs_for_tags = Publication.objects.filter(tags__title__istartswith=q).filter( tags__title__istartswith=q2)
or
pubs_for_tags = Publication.objects.filter(Q(tags__title__istartswith=q), Q( tags__title__istartswith=q2))
I know this is old, but I just ran into the same problem and realized it points at an (as far as I know) undocumented aspect of using Django filters across one-to-many or many-to-many relations. Two conditions made within the same filter apply to the same related object. Two conditions made in separate filters can match two separate related objects.
Another way to think of this is that each complete filter only looks at a single related object at a time, removing a result if all of its related objects fail that filter. Given this, it is extremely rare that you would want two conditions in the same filter using the same keyword.
Consider the following query:
pubs_for_tags = Publication.objects.filter(
tags__title__istartswith=q,
tags__title__iendswith=q2
)
vs
pubs_for_tags = Publication.objects.filter(
tags__title__istartswith=q,
).filter(
tags__title__iendswith=q2
)
The first query finds publications that each have a single tag that both starts with q and ends with q2. When the keyword is the same (note I used two different keywords in my example), you also get the "keyword argument repeated" error.
The second query finds publications that each have a tag that starts with q and have a tag that ends with q2, but it can be two different tags for each publication. From your post, it sounds like this is very close to what you need (just change the "iendswith" to "istartswith"). The only part that could break is if q and q2 are the same or one is a substring of the other. In that instance, a publication could have a single tag that would satisfy both conditions.
Note that all this means using Q objects (which nnmware and Gaurav gave as a possible solution) will not give you the result you want. Having two Q objects in a single filter forces behaviour the same as the first example, but gets around the "keyword argument repeated" error.
pubs_for_tags = Publication.objects.filter(
Q(tags__title__istartswith=q) & Q(tags__title__istartswith=q2)
)
try this
from django.db.models import Q
pubs_for_tags = Publication.objects.filter(Q(tags__title__istartswith=q) & Q( tags__title__istartswith=q2))
check this link
Related
I'm aware of numerous issues raised on the EF7 Github repo, and these still appear to be present with the latest RC2 nightly builds.
The issue appears to be when using OrderBy and Take() when you're trying to Include relations within your query. I believe, according to previous issues raised on Github that the SQL generated within the join is incorrect and does not take into account the OrderBy. After reading replies, people have suggested using Skip(0).Take(x) as a workaround, but unfortunately in my scenario, this didn't work.
In my specific scenario, I'm querying a model based on an ancestor PK. So, in order to work around this, instead of passing the PK straight into the query, I've added the ancestor model to a List<T> and used the following code in the query instead:
Before (not working when Including nested relations): p => p.examplePK == id
After (appears to be working):
p => myList.Select(c => c.myId).Contains(p.examplePK)
I'm not entirely sure why the 2nd example works and I would be grateful of any info that can be given - could there potentially be some client side evaluation going on here instead? From what I gather, the 2nd example will be performing a SQL IN statement, will it not?
Thanks in advance!
I'm querying for test results which are associated with any test set that has a particular tag.
However, this query does not work:
(TestSet.Tags.Name = "foo")
What does work is:
(TestSet.Tags.Name contains "foo")
I would think the first query should work if the second one returns matches with the tag "foo". I presume this is a bug?
I can get around this problem by using the second query, but of course the problem is that this can match a tag named "foo2" as well, so my query can have extra results (potentially many more) and I have to filter them out. Additionally, now I need to have my query fetch the "Tags" as well, so every result I get back is larger because of it.
Yes, as user1195996 suggested this feels like a bug. Your same queries work as expected against defect or user stories. Please work with Rally Support on this issue so we can work to correct it.
In Ruby on rails 3 I want to query on a has_many field of a model as follows:
#project.items.where(:status => 1)
The problem is I'm trying to get the exact opposite result than this. What i want is all items of #project where the status is not 1. Been looking for the answer to this for a while, anyone?
There are many ways to accomplish what you are trying to do, however, some are better than others. If you will always be searching for a hardcoded number (i.e. 1 in this case), then the following solution will work:
#project.items.where('status != 1')
However, if this value is not hard-coded, you are openly vulnerable to SQL injection as Rails will not (cannot) escape this kind of query. As a result, it is preferred among Rails developers to user the following syntax for most custom conditions (those that can't be constructed via Hash):
#project.items.where(['status != ?', 1])
This syntax is slightly confusing, so let me go over it. Basically you are providing the where clause an Array of values. The first value in the array is a String representing the query you want executed. Anywhere you want a value in that string, you place a ?. This serves as a placeholder. Next, you add an element for every question mark in you query. For example, if I had the following:
where(['first_name = ? AND last_name = ?', params[:first_name], params[:last_name]]
Rails will automatically match these up forming the query for you. In that process, it also escapes potentially unsafe characters, preventing injection.
In general, it is preferred to use the Array syntax, even for a hardcoded value. I've been told that pure string conditions in Rails 3.5 will raise a warning (unverified), so it doesn't hurt to get in the process of using the Array syntax now.
MyModel.objects.filter(field__icontains=value) returns all the rows whose field contains value. How to do the opposite? Namely, construct a queryset that returns all the rows whose field is contained in value?
Preferably without using custom SQL (ie only using the ORM) or without using backend-dependent SQL.
field__icontains and similar are coded right into the ORM. The other version simple doesn't exist.
You could use the where param described under the reference for QuerySet.
In this case, you would use something like:
MyModel.objects.extra(where=["%s LIKE CONCAT('%%',field,'%%')"], params=[value])
Of course, do keep in mind that there is no standard method of concatenation across DMBS. So as far as I know, there is no way to satisfy your requirement of avoiding backend-dependent SQL.
If you're okay with working with a list of dictionaries rather than a queryset, you could always do this instead:
qs = MyModel.objects.all().values()
matches = [r for r in qs if value in r[field]]
although this is of course not ideal for huge data sets.
I'm looking for a pattern for performing a dynamic search on multiple tables.
I have no control over the legacy (and poorly designed) database table structure.
Consider a scenario similar to a resume search where a user may want to perform a search against any of the data in the resume and get back a list of resumes that match their search criteria. Any field can be searched at anytime and in combination with one or more other fields.
The actual sql query gets created dynamically depending on which fields are searched. Most solutions I've found involve complicated if blocks, but I can't help but think there must be a more elegant solution since this must be a solved problem by now.
Yeah, so I've started down the path of dynamically building the sql in code. Seems godawful. If I really try to support the requested ability to query any combination of any field in any table this is going to be one MASSIVE set of if statements. shiver
I believe I read that COALESCE only works if your data does not contain NULLs. Is that correct? If so, no go, since I have NULL values all over the place.
As far as I understand (and I'm also someone who has written against a horrible legacy database), there is no such thing as dynamic WHERE clauses. It has NOT been solved.
Personally, I prefer to generate my dynamic searches in code. Makes testing convenient. Note, when you create your sql queries in code, don't concatenate in user input. Use your #variables!
The only alternative is to use the COALESCE operator. Let's say you have the following table:
Users
-----------
Name nvarchar(20)
Nickname nvarchar(10)
and you want to search optionally for name or nickname. The following query will do this:
SELECT Name, Nickname
FROM Users
WHERE
Name = COALESCE(#name, Name) AND
Nickname = COALESCE(#nick, Nickname)
If you don't want to search for something, just pass in a null. For example, passing in "brian" for #name and null for #nick results in the following query being evaluated:
SELECT Name, Nickname
FROM Users
WHERE
Name = 'brian' AND
Nickname = Nickname
The coalesce operator turns the null into an identity evaluation, which is always true and doesn't affect the where clause.
Search and normalization can be at odds with each other. So probably first thing would be to get some kind of "view" that shows all the fields that can be searched as a single row with a single key getting you the resume. then you can throw something like Lucene in front of that to give you a full text index of those rows, the way that works is, you ask it for "x" in this view and it returns to you the key. Its a great solution and come recommended by joel himself on the podcast within the first 2 months IIRC.
What you need is something like SphinxSearch (for MySQL) or Apache Lucene.
As you said in your example lets imagine a Resume that will composed of several fields:
List item
Name,
Adreess,
Education (this could be a table on its own) or
Work experience (this could grow to its own table where each row represents a previous job)
So searching for a word in all those fields with WHERE rapidly becomes a very long query with several JOINS.
Instead you could change your framework of reference and think of the Whole resume as what it is a Single Document and you just want to search said document.
This is where tools like Sphinx Search do. They create a FULL TEXT index of your 'document' and then you can query sphinx and it will give you back where in the Database that record was found.
Really good search results.
Don't worry about this tools not being part of your RDBMS it will save you a lot of headaches to use the appropriate model "Documents" vs the incorrect one "TABLES" for this application.