Django query Select X from Table where Y = Z - python

It's just yet hard to me to clearly understand the way that Django makes queries.
I have two tables:
Table A:
+----+-----+----+
| id |code |name|
+----+-----+----+
Table B:
+----+----+
| id |name|
+----+----+
Value of name of both tables can be equal (or not). What I need to do is to get the value of Table A column code, by comparing both tables' name if Table B does match with Table A in any row.
Example:
Table A:
+----+----+----+
| id |code|name|
+----+----+----+
| 4 | A1 |John|
+----+----+----+
Table B:
+----+----+
| id |name|
+----+----+
| 96 |John|
+----+----+
So, by comparing John (B) with John (A), I need A1 to be returned, since it's the code result in the same row that matches on Table A.
In conclusion I need a Django code to do the query:
a_name = 'John'
SELECT code FROM Table_A WHERE name = a_name
Take into account that I only know the value of table B, therefore I can't get the value of code by Table A's name.

Another approach is to use Django's values and values_list methods. You provide the field name you want data for.
values = Table_A.objects.filter(name=B_name).values('code')
This returns a dictionary with only the code values in it. From the django documentation, https://docs.djangoproject.com/en/2.1/ref/models/querysets/#django.db.models.query.QuerySet.values
Or you can use values_list to format the result as a list.
values = Table_A.objects.filter(name=B_name).values_list('code')
This will return a list of tuples, even if you only request one field. The django documentation, https://docs.djangoproject.com/en/2.1/ref/models/querysets/#django.db.models.query.QuerySet.values_list
To try to make this a little more robust, you first get your list of named values from Table_B. Supplying flat=True creates a true list, as values_list will give you a list of tuples. Then use the list to filter on Table_A. You can return just the code or the code and name. As written, it returns a flat list of user codes for every matching name in Table A and Table B.
b_names_list = Table_B.objects.values_list('name', flat=True)
values =Table_A.objects.filter(name__in=b_names_list).values_list('code', flat=True)

Suppose name of your tables are A and B respectively then:
try:
obj = A.objects.get(name='John')
if B.objects.filter(name='John').exists():
print obj.code # found a match and now print code.
except:
pass

Let's suppose TableA and TableB are django models. Then, your query, may look like this:
a_name = 'John'
it_matches_on_b = ( Table_B
.objects
.filter( name = a_name )
.exists()
)
fist_a = ( Table_A
.objects
.filter( name = a_name )
.first()
)
your_code = fist_a.code if it_matches_on_b and fist_a != None else None
I don't comment code because it is self-explanatory. But write questions on comments if you have.

B_name = ‘whatever’
Table_A.objects.filter(name = B_name)
The above is the basic query if you want to get the db fields values connected to name value from Table_A, based on the fact that you know the name value of Table_B
To get the value:
obj = Table_A.objects.get(name = B_name)
print(obj.name)
print(obj.code) # if you want the 'code' field value

Related

How to use variable column name in filter in Django ORM?

I have two tables BloodBank(id, name, phone, address) and BloodStock(id, a_pos, b_pos, a_neg, b_neg, bloodbank_id). I want to fetch all the columns from two tables where the variable column name (say bloodgroup) which have values like a_pos or a_neg... like that and their value should be greater than 0. How can I write ORM for the same?
SQL query is written like this to get the required results.
sql="select * from public.bloodbank_bloodbank as bb, public.bloodbank_bloodstock as bs where bs."+blood+">0 and bb.id=bs.bloodbank_id order by bs."+blood+" desc;"
cursor = connection.cursor()
cursor.execute(sql)
bloodbanks = cursor.fetchall()
You could be more specific in your questions, but I believe you have a variable called blood which contains the string name of the column and that the columns a_pos, b_pos, etc. are numeric.
You can use a dictionary to create keyword arguments from strings:
filter_dict = {bloodstock__blood + '__gt': 0}
bloodbanks = Bloodbank.objects.filter(**filter_dict)
This will get you Bloodbank objects that have a related bloodstock with a greater than zero value in the bloodgroup represented by the blood variable.
Note that the way I have written this, you don't get the bloodstock columns selected, and you may get duplicate bloodbanks. If you want to get eliminate duplicate bloodbanks you can add .distinct() to your query. The bloodstocks are available for each bloodbank instance using .bloodstock_set.all().
The ORM will generate SQL using a join. Alternatively, you can do an EXISTS in the where clause and no join.
from django.db.models import Exists, OuterRef
filter_dict = {blood + '__gt': 0}
exists = Exists(Bloodstock.objects.filter(
bloodbank_id=OuterRef('id'),
**filter_dict
)
bloodbanks = Bloodbank.objects.filter(exists)
There will be no need for a .distinct() in this case.

How to create a filter in SQLite database across multiple tables?

I am looking for a way to create a number of filters across a few tables in my SQL database. The 2 tables I require the data from are Order and OrderDetails.
The Order table is like this:
------------------------------------
| OrderID | CustomerID | OrderDate |
------------------------------------
The OrderDetails table is like this:
----------------------------------
| OrderID | ProductID | Quantity |
----------------------------------
I want to make it so that it counts the number of instances a particular OrderID pops up in a single day. For example, it will choose an OrderID in Order and then match it to the OrderIDs in OrderDetails, counting the number of times it pops up in OrderDetails.
-----------------------------------------------------------
| OrderID | CustomerID | OrderDate | ProductID | Quantity |
-----------------------------------------------------------
The code I used is below here:
# Execute SQL Query (number of orders made on a particular day entered by a user)
cursor.execute("""
SELECT 'order.*', count('orderdetails.orderid') as 'NumberOfOrders'
from 'order'
left join 'order'
on ('order.orderid' = 'orderdetais.orderid')
group by
'order.orderid'
""")
print(cursor.fetchall())
Also, the current output that I get is this when I should get 3:
[('order.*', 830)]
Your immediate problem is that you are abusing the use of single quotes. If you need to quote an identifiers (table name, column name and the-like), then you should use double quotes in SQLite (this actually is the SQL standard). And an expression such as order.* should not be quoted at all. You are also self-joining the orders table, while you probably want to bring the orderdetails.
You seem to want:
select
o.orderID,
o.customerID,
o.orderDate,
count(*) number_of_orders
from "order" o
left join orderdetails od on od.orderid = o.orderid
group by o.orderID, o.customerID, o.orderDate
order is a language keyword, so I did quote it - that table would be better named orders, to avoid the conflicting name. Other identifiers do not need to be quoted here.
Since all you want from orderdetails is the count, you could also use a subquery instead of aggregation:
select
o.*,
(select count(*) from orderdetails od where od.orderid = o.oderid) number_of_orders
from "order" o

I want make join 2 tables but on 2 things not the typical same, like slug and path , slug abc , and path /article

I have 2 tables one name log contains (path, and log id, etc)
second table name articles contain (slug, id, title)
I want to make a query make join on articles.slug on a log. path
(the problem there path = /articles/slug)
how I make this join
I found pattern called '% %' I tried to use it in join but I don't know how like join on log.path = '/article/' + log.slug
log.path log.count(path)view article.slug
-------------------------------------+- -------|--------------------
/ | 479121 |
/article/candidate-is-jerk | 338647 | candidate-is-jerk
/article/bears-love-berries | 253801 | bears-love-berries
/article/bad-things-gone | 170098 | bad-things-gone
I need make join on this log.path = '/article/' + log.slug
You can express this join in SQL as:
from log l join
article a
on l.path = concat('/article/', a.slug);
or (using standard syntax):
from log l join
article a
on l.path = '/article/' || a.slug;
The second form will handle null values, by ignoring them. The first will (generally but it might depend on the database) return null if either value is null.
You can do join like this
on log.path like concat('%article%',article.slug);

Django : Joining two tables and using extra field from second table for order_by

I have two models A, B
Mysql query is
SELECT a.ID FROM a INNER JOIN b ON ( a.ID = b.id ) WHERE ( b.key = 'vcount' ) AND (a.type = 'abc') AND (a.status = 'done') ORDER BY b.value+0 DESC LIMIT 0, 5
//Here b.value is longtext field, so added 0 to convert to Integer, then sorted.
I need Django query for the same.
I have tried this
A.objects.filter(b__key ="vcount",type = "abc",status = "done").order_by('-b__value')[:5]
but above Django query is giving wrong result, since it is sorting by Ascii value
So need to convert 'value' field to Integer then need to sort it.
I also tried below one but giving errors
xyz = A.objects.filter(b__key ="vcount",type = "abc",status = "done").extra(select={'value_int': "CAST(b__value AS UNSIGNED)"}).order_by('-value_int')[:5]
Suggestions or Help will be appreciated.
The .extra() method's select takes SQL, so the column name should be written as SQL b.value.
xyz = A.objects.filter(b__key ="vcount",type = "abc",status = "done")
.extra(select={'value_int': "CAST(b.value AS UNSIGNED)"})
.order_by('-value_int')[:5]
Since I'm pretty sure this is the issue I'm going to write it anyway...
I'm guessing that value is a DecimalField which is stored internally as a string for indexing, which is why you are seeing strange ordering.
The solution is to change the type of value from DecimalField to FloatField

SQLAlchemy; prevent automatic selection when ordering

With SQLAlchemy ORM querying with PostgreSQL(v9.5); how to prevent the automatic selection when sorting by a column; the sorted column should not be selected.
Hopefully the sample code below makes this more clear.
Example code
A table with an integer 'id', an integer 'object_id' and a string 'text':
id | object_id | text
---------------------
1 | 1 | house
2 | 2 | tree
3 | 1 | dog
The following query should return the distinct object_id as its own id with the most recent text:
query = session.query(
MyTable.object_id.label('id'),
MyTable.text
).\
distinct(MyTable.object_id).\
order_by(MyTable.object_id, MyTable.id.desc())
So far so good; but when I compile the query:
print(query.statement.compile(dialect=postgresql.dialect()))
The mytable.id and mytable.object_id are selected as well, so the column id is specified twice:
SELECT DISTINCT ON (mytable.object_id) mytable.object_id AS id,
mytable.text,
mytable.object_id,
mytable.id
FROM mytable
ORDER BY mytable.object_id,
mytable.id DESC
You can try it. It should work:
query = session.query(MyTable.object_id.distinct().label('id'), MyTable.text).order_by(MyTable.object_id, MyTable.id.desc())

Categories