How to query on joined table attribute in sqlachemy - python

I am using sql alchemy in my project.
I have one problem when two or more tables are joined or have foreign key relation then i am unable to query on joined tables attribute in where condition.
Eg. I have notice table and a user table user.id is foreign key of notice.sender
now I want to search notice by user.name
notice table:[id, sender(FK user.id), receiver(FK user.id), subject, message, status]
user table: [id, name, email, address, status]
Join in notice model:
sender_user = relationship('User', primaryjoin='Notice.sender==user.id', backref=backref("sender_user"))
receiver_user = relationship('User', primaryjoin='Notice.receiver==user.id', backref=backref("receiver_user"))
SQL alchemy filter query:
user_name='john'
notice=db_session.query(Notice)
notice = notice.filter(Notice.sender_user.name == user_name)
Following query doesn't works:
notice=db_session.query(Notice)
notice = notice.filter(Notice.user.name == user_name)
Please help!

You need to acquire a session object, then do:
query = session.query(Notice).filter(Notice.sender_user.name == user_name)
results = query.all()
If that does not work (you don't get the results you expect), try doing this:
session.query(Notice, User.name).filter((Notice.sender_user.id == User.id) & (User.name == user_name))
results = query.all()
I suppose you also have a field called sender which is the id of the user. Then, this should also work:
session.query(Notice, User.name).filter((Notice.sender == User.id) & (User.name == user_name))
Retry all of them, I made some small modifications. (you can see them in revision history). It would be weird if they don't work... (If they don't, try posting the question on the SQLAlchemy mailing list)

Related

How to show different data to different users in flask application?

I have created a flask application and using mysql as DB backend and this is used by multiple users simultaneously.
The problem I'm having is,In my homepage a select query is performed and data is displayed to the user but same data is showing to all users.it should be unique. I have tried to lock the row by using FOR UPDATE while selecting the row. I know that I'm not updating the row,so the transaction will be closed when the function ends and the row will be released from lock.
How to overcome this problem?
Expected output: Each user should get different data from the table.(Even when they refresh)
#is_logged_in
#app.route('/')
def index():
conn = mysql.connection
cur = conn.cursor()
cur.execute("select mylist ,myurl ,swatch,parent from image_links where status =%s LIMIT 1 FOR UPDATE",("fetched",))
parent = cur.fetchall()
for row in parent:
mylistitems = row[0].split(",")
swatches = row[2].split(",")
myurlsitems = row[1].split(",")
pid = row[3]
if asinlist != ['']:
merged = tuple(zip(mylistitems ,myurlsitems ,swatches))
return render_template('home.html',firstimage= myurlsitems[0],merged=merged)
else:
cur.execute("UPDATE asin_links SET status = %s WHERE pid= %s", ("invalid",pid,))
conn.commit()
return redirect(url_for('index'))
I can't see any "current user" specific parameters used in your sql query or any data filtering decided on some user ID.
Basically, if you are running the same code, same query for all requests on this endpoint, it will never be really unique. You need to add some user specific checks so you can differentiate the output for the current requesting user.
Depending on your use-case and database models, if the data in the table image_links is also created/inserted by some user action you might want additionally save some user ID alongside these values, eg. by extending the table model with another "user_id" column and on insert also add the id of the current user.
You are using some auth decorator #is_logged_in, if you are already handling users in some table then the another user_id column could be a reference to the respective user's primary key. Then, in your example, you would just add additional where user_id = check with the current user's primary key.
As I see in this SQL query:
SELECT mylist, myurl, swatch, parent FROM image_links WHERE status
perhaps you did specify the related user to get its own specific data, try to replace that last "where" with:
WHERE id = (user.id) --> user object
or you could use the AND keyword, something like
WHERE status = (x) AND id = (y)

SQL Query returning "None" instead of row

I'm working on a light login, and have a tabled titled Users. I'm trying to take my login form POST body and verify it across the database.
Values from form:
user = request.form['username']
password = request.form['password']
SQL Statement:
conn = sqlite3.connect(db)
cur = conn.cursor()
cur.execute("SELECT * FROM Users WHERE Username LIKE '(%s)'" % user)
row = cur.fetchone()
Users Table:
So on a POST request from my form, here is what is printed:
Print(user, password) = ph104694 Password123
Print(row) = None
So you can see the row is being returned as None when the data absolutely exists. If I change user to something I know is incorrect, I'm getting the same results, but if I change the table from Users to something like Users2 I'm met with a no table exists error which is fine. So despite matching data existing something about my statement isn't allowing it to produce that row. Any ideas?
You're search expression is evaluating to (ph104694) which clearly doesn't exist in the data you showed.
There is no reason to use the LIKE operator here and it probably runs counter to what you want to do (match the single record exactly matching the user ID that was entered).
This is the classic example of code that is subject to an SQL injection attack. You should never, never, ever use string interpolation to build an SQL string like this. Instead, use parameter substitution.
Taken all together, you want something like this:
cur.execute("SELECT * FROM Users WHERE Username = ?", [user])
Your query string evaluates to "SELECT * FROM Users WHERE Username LIKE '(ph104694)'".
Note the parentheses which aren't in the actual username.
Also, you almost certainly don't want to use LIKE.
What you want is "SELECT * FROM Users WHERE Username = 'ph104694'"
Which would create with "SELECT * FROM Users WHERE Username = '{user}'".format(user=user)
Also, you can (and should) parameterize this as
cur.execute("SELECT * FROM Users WHERE Username = :user", {user: user})

SQLAlchemy left join using subquery

Lets say there's a table "posts" which contains blog posts, and another table "favorites" which links a username to a post. Many users can favorite a post, so the relationship is one post to many favorites.
I am trying to figure out the syntax to join posts to favorites, but I only want those favorites where the user is the current user.
I want some thing like:
current_user = 'testuser'
posts.query.outerjoin(favorites, and_(posts.post_id == favorites.post_id, favorites.username == current_user)).limit(10).all()
This get me really close, except it seems like the "favorites.username == current_user" condition is basically getting ignored. This is what I am looking for in actual SQL:
SELECT *
FROM posts p
LEFT JOIN (
SELECT * FROM favorites f WHERE f.user_id = 'testuser'
) ff ON ff.post_id = p.post_id
LIMIT 10
It's also worth mentioning that I have defined the relationship on posts like:
favorites = db.relationship("favorites")
And I have defined the foreign key on favorites like this:
post_id = db.Column(db.String(255), db.ForeignKey('posts.post_id'))
How can I accomplish this in SQLAlchemy?
Really you just need to replace the outerjoin with join, and the filter would work just fine.
Also, if your favorites table contains no additional information and only links users and posts, you should consider simply defining a `Many to Many' relationship. In the documentation examples Parent/Child would be your User/Post.
Update-1: just to answer second part of the question given your comment, the query below should give you an idea:
current_user = 2
subq = (db.session.query(favorites)
.filter(favorites.user_id == current_user).subquery('ff'))
q = (db.session.query(posts, subq.c.score)
.outerjoin(subq, subq.c.post_id == posts.post_id))
q = q.order_by(subq.c.score.desc())
for post, score in q:
print(post, score)

Not able to get the id of the group

if is_admin == True:
admin_users = Group(name = 'Admin')
try:
admin_users.save()
except:
log.info("Admin Group already exists")
pass
group_id = Group.objects.get(name='Admin').id
If in the data that I get 'is_admin' is true then I will create the group 'Admin' if not existed then save it and fetches the id of that group-'Admin'. This id will be saved in the userinfo with Group as a foreign key.
The following query should give me the id of that group.
group_id = Group.objects.get(name='admin').id
Instead it is saying
current transaction is aborted, commands ignored until end of transaction block
I am using the postgresql database I don't know why it is giving me the error while executing this query. Please tell me how to write the query.
What are you trying to achieve is already in django: get_or_create. Using this your code should look like
group, created = Group.objects.get_or_create(name='Admin')
if created:
log.info("Admin Group already exists")
group_id = group.pk
pk is a convenience property on all django models that always point to a primary key field, no matter if it's autocreated or specified explicitly.

How to query database by id using SqlAlchemy?

I need to query a SQLAlchemy database by its id something similar to
User.query.filter_by(username='peter')
but for id. How do I do this? [Searching over Google and SO didn't help]
Query has a get function that supports querying by the primary key of the table, which I assume that id is.
For example, to query for an object with ID of 23:
User.query.get(23)
Note: As a few other commenters and answers have mentioned, this is not simply shorthand for "Perform a query filtering on the primary key". Depending on the state of the SQLAlchemy session, running this code may query the database and return a new instance, or it may return an instance of an object queried earlier in your code without actually querying the database. If you have not already done so, consider reading the documentation on the SQLAlchemy Session to understand the ramifications.
You can query a User with id = 1 like this
session.query(User).get(1)
get() is not as your expected sometimes. If your transaction was done:
>>> session.query(User).get(1)
[SQL]: BEGIN (implicit)
[SQL]: SELECT user.id AS user_id, user.name AS user_name, user.fullname AS user_fullname
FROM user
WHERE user.id = ?
[SQL]: (1,)
<User(u'ed', u'Ed Jones')>
If you are in a transaction, get() will give you the result object in memory without query the database:
>>> session.query(User).get(1)
<User(u'ed', u'Ed Jones')>
better to use this:
>>> session.query(User.name).filter(User.id == 1).first()
[SQL]: SELECT user.name AS user_name
FROM user
WHERE user.id = ?
LIMIT ? OFFSET ?
[SQL]: (1, 1, 0)
(u'Edwardo',)
If you use tables reflection you might have problems with the solutions given.
(The previous solutions here didn't work for me).
What I ended up using was:
session.query(object.__class__).get(id)
(object was retrieved by reflection from the database, this is why you need to use .__class__)
I hope this helps.
First, you should set id as the primary key.
Then you could use the query.get() method to query objects by id which is already the primary key.
Since the query.get() method to query objects by the primary key.
Inferred from Flask-SQLAlchemy documentation
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
db = SQLAlchemy()
db.init_app(app)
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
def test():
id = 1
user = User.query.get(id)

Categories

Resources