How to rewrite deprecated DDL() statement in SQLAlchemy 0.7+ - python

So far I have used the following statements in SQLAlchemy to implement table inheritance via ALTER TABLE:
inherit = "ALTER TABLE %(fullname)s INHERIT parent_table"
DDL(inherit, on='postgresql').execute_at("after-create", child_table)
This is deprecated in SQLAlchemy now, and I am a bit confused about the new method through
DDLEvents, DDLElement.execute_if(), listeners and events in general.
What is the correct way to create and execute DDL() constructs in SQLAlchemy 0.7+?

Look at an example in documentation, your code can be rewritten as:
event.listen(child_table, "after-create", DDL(inherit).execute_if(dialect='postgresql'))

Related

In SQLAlchemy, is there a way to eager-load multiple aliased selectables of the same class using one query?

I have an SQLAlchemy mapped class MyClass, and two aliases for it. I can eager-load a relationship MyClass.relationship on each alias separately using selectinload() like so:
alias_1, alias_2 = aliased(MyClass), aliased(MyClass)
q = session.query(alias_1, alias_2).options(
selectinload(alias_1.relationship),
selectinload(alias_2.relationship))
However, this results in 2 separate SQL queries on MyClass.relationship (in addition to the main query on MyClass, but this is irrelevant to the question). Since these 2 queries on MyClass.relationship are to the same table, I think that it should be possible to merge the primary keys generated within the IN clause in these queries, and just run 1 query on MyClass.relationship.
My best guess for how to do this is:
alias_1, alias_2 = aliased(MyClass), aliased(MyClass)
q = session.query(alias_1, alias_2).options(
selectinload(MyClass.relationship))
But it clearly didn't work:
sqlalchemy.exc.ArgumentError: Mapped attribute "MyClass.relationship" does not apply to any of the root entities in this query, e.g. aliased(MyClass), aliased(MyClass). Please specify the full path from one of the root entities to the target attribute.
Is there a way to do this in SQLAlchemy?
So, this is exactly the same issue we had. This docs explains how to do it.
You need to add selectin_polymorphic. For anyone else if you are using with_polymorphic in your select then remove it.
from sqlalchemy.orm import selectin_polymorphic
query = session.query(MyClass).options(
selectin_polymorphic(MyClass, [alias_1, alias_2]),
selectinload(MyClass.relationship)
)

How can I write SQL statements for psycopg2 for PostreSQL and sqlite3?

I use the psycopg2 library for PostgreSQL in python for my production environment but I want to test my code with the sqlite3 library. The problem is that psycopg2 uses %s as a placeholder for parameter substitution, whereas sqlite3 uses ?.
I am not happy with the code I got now, it looks like this:
queries = {
'is_admin': "SELECT * FROM admins WHERE user_id = ?;",
}
if dbtype == 'postgres':
for key, value in queries.items():
queries[key] = value.replace('?', '%s')
It's kind of an ugly hack but I don't want to write all my queries two times, so what's the best solution for this problem?
Using simple ? to %s string replacement is dangerous, you may break your query, or harm the actual data in all sorts of unpredictable ways which could be difficult to debug.
Look into the "SQL for humans" records package that provides a uniform parameterization style for all the supported databases.
Note that records achieves the database-agnostic parameterization style only because of using the text() function from the SQLAlchemy package. You may as well use it directly:
The advantages text() provides over a plain string are backend-neutral
support for bind parameters, per-statement execution options, as well
as bind parameter and result-column typing behavior, allowing
SQLAlchemy type constructs to play a role when executing a statement
that is specified literally.

SELECT UNCOMPRESS(text) FROM with sqlalchemy

I store the MySQL Compress function to insert compressed blob data to the database.
In a previous question I was instructed to to use
func.compress
( mysql Compress() with sqlalchemy )
The problem now is that I want to read also the data from the database.
In mysql I would have done
SELECT UNCOMPRESS(text) FROM ...
probably I should use a getter in the class.
I tried to do somethin like:
get_html(self):
return func.uncompress(self.text)
but this does not work. It returns an sqlalchemy.sql.expression.Function and not the string.
Moreover I could not find which functions contains sqlalchemy's func.
Any ideas on how i could write a getter in the object so I get back the uncompressed data.
func is actually a really fancy factory object for special function objects which are rendered to SQL at query time - you cannot evaluate them in Python since Python would not know how your database implements compress(). That's why it doesn't work.
SQLAlchemy lets you map SQL expressions to mapped class attributes. If you're using the declarative syntax, extend your class like so (it's untested, but I'm confident this is the way to go):
from sqlalchemy.orm import column_property
class Demo(...):
data_uncompressed = column_property(func.uncompress(data))
Now whenever SQLAlchemy loads an instance from the database, the SELECT query will contain SELECT ..., UNCOMPRESS(demotable.data), ... FROM demotable.
Edit by Giorgos Komninos:
I used the
http://docs.sqlalchemy.org/en/rel_0_7/orm/mapper_config.html#using-a-plain-descriptor
and it worked.

SQLAlchemy - INSERT OR REPLACE equivalent

does anybody know what is the equivalent to SQL "INSERT OR REPLACE" clause in SQLAlchemy and its SQL expression language?
Many thanks -- honzas
What about Session.merge?
Session.merge(instance, load=True, **kw)
Copy the state an instance onto the persistent instance with the same identifier.
If there is no persistent instance currently associated with the session, it will be loaded. Return the persistent instance. If the given instance is unsaved, save a copy of and return it as a newly persistent instance. The given instance does not become associated with the session. This operation cascades to associated instances if the association is mapped with cascade="merge".
from http://www.sqlalchemy.org/docs/reference/orm/sessions.html
Session.save_or_update(model)
I don't think (correct me if I'm wrong) INSERT OR REPLACE is in any of the SQL standards; it's an SQLite-specific thing. There is MERGE, but that isn't supported by all dialects either. So it's not available in SQLAlchemy's general dialect.
The cleanest solution is to use Session, as suggested by M. Utku. You could also use SAVEPOINTs to save, try: an insert, except IntegrityError: then rollback and do an update instead. A third solution is to write your INSERT with an OUTER JOIN and a WHERE clause that filters on the rows with nulls.
You can use OR REPLACE as a so-called prefix in your SQLAlchemy Insert -- the documentation for how to place OR REPLACE between INSERT and INTO in your SQL statement is here

Best way to access table instances when using SQLAlchemy's declarative syntax

All the docs for SQLAlchemy give INSERT and UPDATE examples using the local table instance (e.g. tablename.update()... )
Doing this seems difficult with the declarative syntax, I need to reference Base.metadata.tables["tablename"] to get the table reference.
Am I supposed to do this another way? Is there a different syntax for INSERT and UPDATE recommended when using the declarative syntax? Should I just switch to the old way?
well it works for me:
class Users(Base):
__tablename__ = 'users'
__table_args__ = {'autoload':True}
users = Users()
print users.__table__.select()
...SELECT users.......
via the __table__ attribute on your declarative class
There may be some confusion between table (the object) and tablename (the name of the table, a string). Using the table class attribute works fine for me.

Categories