search for django-objects tagged with all tags in a set - sql

In my django-project have a search function where you can specify tags, like "apple, banana" and by that query for objects of a certain model, tagged with taggit. When I do:
tag_set = Tag.objects.filter(Q(name__in=tag_list))
query_set = Model.objects.filter(Q(tags__in=tag_set))
this gives me objects tagged with either "apple" OR "banana". But I want the AND operator... I tried:
query_set = Model.objects.filter(reduce(operator.and_, (Q(tags__in=x) for x in tag_set)))
but then I get 'Tag' object is not iterable.
Any help?

You can work with:
queryset = Model.objects.all()
for tag in tag_list:
queryset = queryset.filter(tags__name=tag)
This will make a JOIN for each tag, and thus eventually the queryset will only contain Model items that have all the necessary tags.
Another approach is counting the number of matched tags, so:
from django.db.models import Count
tag_set = set(tag_list)
Model.objects.filter(tag__name__in=tag_set).alias(
ntags=Count('tags')
).filter(ntags=len(tag_set))

Related

want to assert inner list in karate

I have this kind of response in my API and I want to check that any of the list doesn't contain duplicate values.
[["1100","1100"],["123456"],["123456"],["123456"],["123516","110011"],["123515","110010"],["123514","110009"],["123513","110008"]]
when I use * match response == karate.distinct(response) , it compares all the values and not the values within the inner list like below
[["1100","2200"],["123456"],["123516","110011"],["123515","110010"],["123514","110009"],["123513","110008"]]
I only want to check whether inner list doesn't contain duplicate values, regardless of outer list elements.
This is the parent question https://stackoverflow.com/a/71807872/3664382, but now I'm stuck here -
Use match each: https://github.com/karatelabs/karate#match-each
And combine it with a "self" validation: https://github.com/karatelabs/karate#self-validation-expressions
* def fun = function(x){ return karate.match(x, karate.distinct(x)).pass }
* match each response == '#? fun(_)'
I have no idea how people end up with these weird situations. Please read this and I hope it makes sense: https://stackoverflow.com/a/54126724/143475
For completeness, you should take some time to understand JsonPath. This below will "flatten" the entire response into a single array:
* def temp = $response[*][*]

Query list index with django

i have a problem with django when i use these two arrays:
institution_ids [(2,), (16,)]
project_ids [(3,), (1,)]
in this query:
queryset = Patient.active.filter(tss_id__in=institution_ids, project_id__in = project_ids)
it gives me back all the combinations, but I need this kind of result:
queryset = Patient.active.filter(tss_id=institution_ids[0], project_id = project_ids[0])
queryset += Patient.active.filter(tss_id=institution_ids[1], project_id = project_ids[1])
how can i do?
Thanks
Giuseppe
What you search for is an OR statement.
You can do it using Q object.
In Django, we cannot directly use the OR operator to filter the
QuerySet. For this implementation, we have to use the Q() object. By
using the Q() object in the filter method, we will be able to use the
OR operator between the Q() objects.
For example-
If you want to get all objects with tss_id in institution array and all objects with project__id__in projects_id array you will use it like this.
queryset = Patient.active.filter(Q(tss_id__in=institution_ids) | project_id__in = project_ids))
Pay attention- you need to import Q.
Another option -
Using union
New in Django 1.11. Uses SQL’s UNION operator to combine the results of two or more QuerySets.
The UNION operator selects only distinct values by default. To allow duplicate values, use the all=True argument.
For example :
queryset = Patient.active.filter(tss_id=institution_ids[0], project_id = project_ids[0])
queryset2 = Patient.active.filter(tss_id=institution_ids[1], project_id = project_ids[1])
Combined_queryset = queryset.union(queryset2)

using .where with .find

I am wondering how I can use where cause with the ActiveRecord find method.
Here is the code I am using:
Supplier.joins(:products).find(params[:id]).where('suppliers.permalink = ? AND variants.master = ?', params[:id], TRUE)
which gives me:
undefined method `where' for #<Supplier:0x007fe49b4eb330>
Supplier.joins(:products).find(params[:id]).where('suppliers.permalink = ? AND variants.master = ?', params[:id], TRUE)
What you're doing here is finding the first record with the id contained in params[:id], then trying to run a where statement on that single record. where only works when run against the model itself.
The confusing part here is that you are using params[:id] both for the primary key (find searches the id field) but then also comparing it to the permalink column in the where clause.
To explain the usage of both methods:
find will search for result(s) from the table, matching the argument you provide it to the id field. You can pass in multiple id's and this method is mostly used to select a row that you know exists, by id. Most commonly it is used with a single id and returns a single instance.
where is used to find all results from the table that match the clause and return a collection of records. You can then refine these results or select one, for example by using .first:
Supplier.joins(:products).where('suppliers.permalink = ? AND variants.master = ?', params[:permalink], true).first
(Note that you're using joins(:products) but then querying variants table. Is this incorrect?)
Supplier.joins(:products).where('suppliers.permalink = ? AND variants.master = ?', params[:id], TRUE).find(params[:id])

How to specify multiple values in where with AR query interface in rails3

Per section 2.2 of rails guide on Active Record query interface here:
which seems to indicate that I can pass a string specifying the condition(s), then an array of values that should be substituted at some point while the arel is being built. So I've got a statement that generates my conditions string, which can be a varying number of attributes chained together with either AND or OR between them, and I pass in an array as the second arg to the where method, and I get:
ActiveRecord::PreparedStatementInvalid: wrong number of bind variables (1 for 5)
which leads me to believe I'm doing this incorrectly. However, I'm not finding anything on how to do it correctly. To restate the problem another way, I need to pass in a string to the where method such as "table.attribute = ? AND table.attribute1 = ? OR table.attribute1 = ?" with an unknown number of these conditions anded or ored together, and then pass something, what I thought would be an array as the second argument that would be used to substitute the values in the first argument conditions string. Is this the correct approach, or, I'm just missing some other huge concept somewhere and I'm coming at this all wrong? I'd think that somehow, this has to be possible, short of just generating a raw sql string.
This is actually pretty simple:
Model.where(attribute: [value1,value2])
Sounds like you're doing something like this:
Model.where("attribute = ? OR attribute2 = ?", [value, value])
Whereas you need to do this:
# notice the lack of an array as the last argument
Model.where("attribute = ? OR attribute2 = ?", value, value)
Have a look at http://guides.rubyonrails.org/active_record_querying.html#array-conditions for more details on how this works.
Instead of passing the same parameter multiple times to where() like this
User.where(
"first_name like ? or last_name like ? or city like ?",
"%#{search}%", "%#{search}%", "%#{search}%"
)
you can easily provide a hash
User.where(
"first_name like :search or last_name like :search or city like :search",
{search: "%#{search}%"}
)
that makes your query much more readable for long argument lists.
Sounds like you're doing something like this:
Model.where("attribute = ? OR attribute2 = ?", [value, value])
Whereas you need to do this:
#notice the lack of an array as the last argument
Model.where("attribute = ? OR attribute2 = ?", value, value) Have a
look at
http://guides.rubyonrails.org/active_record_querying.html#array-conditions
for more details on how this works.
Was really close. You can turn an array into a list of arguments with *my_list.
Model.where("id = ? OR id = ?", *["1", "2"])
OR
params = ["1", "2"]
Model.where("id = ? OR id = ?", *params)
Should work
If you want to chain together an open-ended list of conditions (attribute names and values), I would suggest using an arel table.
It's a bit hard to give specifics since your question is so vague, so I'll just explain how to do this for a simple case of a Post model and a few attributes, say title, summary, and user_id (i.e. a user has_many posts).
First, get the arel table for the model:
table = Post.arel_table
Then, start building your predicate (which you will eventually use to create an SQL query):
relation = table[:title].eq("Foo")
relation = relation.or(table[:summary].eq("A post about foo"))
relation = relation.and(table[:user_id].eq(5))
Here, table[:title], table[:summary] and table[:user_id] are representations of columns in the posts table. When you call table[:title].eq("Foo"), you are creating a predicate, roughly equivalent to a find condition (get all rows whose title column equals "Foo"). These predicates can be chained together with and and or.
When your aggregate predicate is ready, you can get the result with:
Post.where(relation)
which will generate the SQL:
SELECT "posts".* FROM "posts"
WHERE (("posts"."title" = "Foo" OR "posts"."summary" = "A post about foo")
AND "posts"."user_id" = 5)
This will get you all posts that have either the title "Foo" or the summary "A post about foo", and which belong to a user with id 5.
Notice the way arel predicates can be endlessly chained together to create more and more complex queries. This means that if you have (say) a hash of attribute/value pairs, and some way of knowing whether to use AND or OR on each of them, you can loop through them one by one and build up your condition:
relation = table[:title].eq("Foo")
hash.each do |attr, value|
relation = relation.and(table[attr].eq(value))
# or relation = relation.or(table[attr].eq(value)) for an OR predicate
end
Post.where(relation)
Aside from the ease of chaining conditions, another advantage of arel tables is that they are independent of database, so you don't have to worry whether your MySQL query will work in PostgreSQL, etc.
Here's a Railscast with more on arel: http://railscasts.com/episodes/215-advanced-queries-in-rails-3?view=asciicast
Hope that helps.
You can use a hash rather than a string. Build up a hash with however many conditions and corresponding values you are going to have and put it into the first argument of the where method.
WRONG
This is what I used to do for some reason.
keys = params[:search].split(',').map!(&:downcase)
# keys are now ['brooklyn', 'queens']
query = 'lower(city) LIKE ?'
if keys.size > 1
# I need something like this depending on number of keys
# 'lower(city) LIKE ? OR lower(city) LIKE ? OR lower(city) LIKE ?'
query_array = []
keys.size.times { query_array << query }
#['lower(city) LIKE ?','lower(city) LIKE ?']
query = query_array.join(' OR ')
# which gives me 'lower(city) LIKE ? OR lower(city) LIKE ?'
end
# now I can query my model
# if keys size is one then keys are just 'brooklyn',
# in this case it is 'brooklyn', 'queens'
# #posts = Post.where('lower(city) LIKE ? OR lower(city) LIKE ?','brooklyn', 'queens' )
#posts = Post.where(query, *keys )
now however - yes - it's very simple. as nfriend21 mentioned
Model.where(attribute: [value1,value2])
does the same thing

Is there a way to store PyTable columns in a specific order?

It seems that the PyTable columns are alphabetically ordered when using both dictionary or class for schema definition for the call to createTable(). My need is to establish a specific order and then use numpy.genfromtxt() to read and store my data from text. My text file does not have the variable names included alphabetically as they are for the PyTable.
For example, assuming text file is named mydata.txt and is organized as follows:
time(row1) bVar(row1) dVar(row1) aVar(row1) cVar(row1)
time(row2) bVar(row2) dVar(row2) aVar(row2) cVar(row2)
...
time(rowN) bVar(rowN) dVar(rowN) aVar(rowN) cVar(rowN)
So, the desire is to create a table that is ordered with these columns
and then use the numpy.genfromtxt command to populate the table.
# Column and Table definition with desired order
class parmDev(tables.IsDescription):
time = tables.Float64Col()
bVar = tables.Float64Col()
dVar = tables.Float64Col()
aVar = tables.Float64Col()
cVar = tables.Float64Col()
#...
mytab = tables.createTable( group, tabName, paramDev )
data = numpy.genfromtxt(mydata.txt)
mytab.append(data)
This is desired because it is straightforward code and is very fast. But, the PyTable columns are always ordered alphabetically and the appended data is ordered according to the desired order. Am I missing something basic here? Is there a way to have the order of the table columns follow the class definition order instead of being alphabetical?
Yes, you can define an order in tables in several different ways. The easiest one is to use the pos parameter for each column. See the docs for the Col class:
http://pytables.github.io/usersguide/libref/declarative_classes.html#the-col-class-and-its-descendants
For your example, it will look like:
class parmDev(tables.IsDescription):
time = tables.Float64Col(pos=0)
bVar = tables.Float64Col(pos=1)
dVar = tables.Float64Col(pos=2)
aVar = tables.Float64Col(pos=3)
cVar = tables.Float64Col(pos=4)
Hope this helps