[sqlalchemy] Re: SQLAlchemy ORM Object caching with relationships and invalidation

2012-09-27 Thread David McKeone
Hi Mike,

I'll let the others add more detail about your questions, but for the broad 
strokes I thought I'd add that I ran into similar issues with my simple 
caching method and ultimately ended up using the new Dogpile.cache stuff 
that Mike recommended on his 
bloghttp://techspot.zzzeek.org/2012/04/19/using-beaker-for-caching-why-you-ll-want-to-switch-to-dogpile.cache/.
 
  (The example file is here: 
https://groups.google.com/d/msg/sqlalchemy/MrKA6AygZ14/o95dmUdLS70J )  It 
is far more integrated with the internals of SQLAlchemy relationship 
management, so it may behave better.


On Thursday, September 27, 2012 7:28:12 AM UTC+2, mikepk wrote:

 Unlike most of the SQLAlchemy caching examples, I'm not using query-level 
 caching but rather caching at the instance / object level. I'm using the 
 ORM and I have a SQLAlchemy object that I load and occasionally store in a 
 second level cache. I have a custom 'get' loading function that checks the 
 second level cache based on primary key and returns the cached copy if 
 present and populates the cache if not.

 I also have an event handler on 'after_commit' that checks the session for 
 dirty objects that are cached (with a simple class property of 
 __cached__=True) and does either an invalidate or write-back to the cache 
 when these objects are dirty and cached.

 This pattern is pretty simple and works great.

 My problem is that I'd like to be able to use this same (or similar) 
 pattern for more complex SQLAlchemy objects containing relationships. I'd 
 like the cache to contain not only the 'base' object but all (lazy) loaded 
 related obejcts. I have no problem storing and retrieving these objects 
 (and relationships) from the cache, my problem comes from the 
 invalidation/write-back part.

 Lets say I have object A that's in the cache and it has a relationship, 
 A.B that was stored along with it in the cache. If I retrieve A from the 
 cache I can get A.B and I get the cached copy of B. If B is modified, 
 however, then my simple cache invalidator event handler doesn't see that B 
 is cached (no __cached__ property on B) and B gets committed to the 
 database without the cached copy of A being invalidated. Now subsequent 
 cache hits of A will have a stale A.B relationship.

 So my question is, is there a clean / simple way to mark A for 
 invalidation when B is modified? I've come up with a few schemes but all of 
 them seem brittle, complicated, and my intuition is telling me that I'm 
 reinventing the wheel; that some facility in SQLAlchemy itself may be 
 useful in walking this relationship graph to find loaded, connected 
 relationships who's cached represenations might need to be invalidated. 
 Alternatively, is there another pattern that would be better suited to this 
 kind of object-level caching?

 Thanks!
 -Mike


-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/sqlalchemy/-/s9rf5eY9f2IJ.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] Dogpile.cache w/ SQLAlchemy

2012-09-26 Thread David McKeone
This example has worked really well so far, but I thought I'd mention that 
I ran into few small things and made some changes.

1) This is was minor. I wanted to be able to use the cache_regions on 
multiple databases from the same program so I made the CachingQuery class 
take a parameter with the regions dict it operates on -- simple enough, and 
similar to the Beaker example which takes a cache manager instance.

2) This was a little more interesting.  I replaced an existing simplistic 
caching implementation that stored database results with the new 
dogpile.cache implementation and I saw my request times slow down from 16ms 
to 66ms.  It kind of shocked me that it was so much slower, so I ran 
cProfile and gprof2dot against it to see what was happening.  I found out 
that the key generation algorithm in _key_from_query -- specifically 
visitors.traverse -- was causing the slow-down.  Once I added a small 
feature to use explicit cache keys, it was back to normal.  Admittedly the 
tables I'm caching in this case are quite large; three preference tables 
that have 100+ columns each.  However, I think it does serve as a bit of a 
warning, since I imagine the traverse only gets slower as the query gets 
more complicated (although I haven't tested that).  Automatic cache-key 
generation based on the query is nice, but there is certainly a price to be 
paid in some circumstances.

Anyway, thanks again for the example Mike.  I imagine that some (maybe all) 
of these things could be due to the fact that it is just an example, but 
since it is new I thought I'd pass along my experience.  It's simplicity 
certainly helped me to see where all the pieces fit and to start making 
these changes.


On Monday, September 24, 2012 4:15:29 PM UTC+2, Michael Bayer wrote:

 yes, the example in 0.8 should be changed to this, but I haven't done it 
 yet.   dogpile's usage is similar to Beaker as far as the general calling 
 pattern.   A tutorial format of the example using dogpile is attached.



-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/sqlalchemy/-/hO3TuPbT8AAJ.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] Dogpile.cache w/ SQLAlchemy

2012-09-26 Thread David McKeone
Fair enough about the example stuff; I kind of figured, but thought I'd 
just share my experience.  It's such a fine-line between authors getting a 
bead on real-world usage vs. hearing the same question over and over again.

Previously, I had it just using the binds that were in the Query, but we 
 had cases where bound parameters were embedded in the statement too 
 affecting things.   So as a quick fix I changed it to just traverse the 
 whole statement, but this can be optimized significantly more than it is. 
  It's the way it is so that it works more completely on the first 
 go-around.


Is there a thread I can pull at here?  I'd love to here about performant 
key generation options that are more flexible than explicit cache keys 
(obviously that is highly prone to developer error).   Looking at the query 
class, I'm guessing you are still using md5(unicode(query.statement)) for 
the query portion of the key, but what are you using for binds?  (Sorry, 
not quite familiar with the internals of SQLAlchemy yet -- and I can't find 
that attribute or anything similar in the source)  Are there other 
alternatives for cache keys that are worth exploring?  (and feel free to 
just post links or what have you, I'm happy to do the reading)

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/sqlalchemy/-/JvefOSuw1FwJ.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



[sqlalchemy] Dogpile.cache w/ SQLAlchemy

2012-09-24 Thread David McKeone
As per this 
comment: 
http://techspot.zzzeek.org/2012/04/19/using-beaker-for-caching-why-you-ll-want-to-switch-to-dogpile.cache/#comment-503780670

Has any work been put into an example for using Dogpile.cache with 
SQLAlchemy?  I'm about to embark on implementing caching and I don't want 
to re-invent the wheel by creating my own adaptation if I don't need to.


-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/sqlalchemy/-/zf0HBD7s7SwJ.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] Dogpile.cache w/ SQLAlchemy

2012-09-24 Thread David McKeone
Great, thanks Mike!

On Monday, September 24, 2012 4:15:29 PM UTC+2, Michael Bayer wrote:

 yes, the example in 0.8 should be changed to this, but I haven't done it 
 yet.   dogpile's usage is similar to Beaker as far as the general calling 
 pattern.   A tutorial format of the example using dogpile is attached.



-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/sqlalchemy/-/ULgsSiDYpfIJ.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] SELECT * FROM function() with declarative

2012-09-21 Thread David McKeone
ok, I think I found the solution.  Thought I'd post what I did and what I 
tried; partly because it might help someone else and partly because someone 
may have suggestions for a better way.

This is what worked:

my_function = func.my_function(...args...)
func_subquery =  select(['id'], from_obj=[my_function])
results = 
session.query(Table1).join(Table2).filter(Table1.id.in_(func_subquery))

and results in a query that looks like this:

SELECT table1.id, table1.col1, table1.col2... FROM table1 JOIN table2 ON 
table1.t2_id = table2.id WHERE table1.id IN( SELECT id FROM 
my_function(...args...) )

This differs somewhat from what I was initially thinking:

SELECT table1.id, table1.col1, table1.col2... FROM (SELECT * FROM 
my_function(...args...)) as table1 JOIN table2 ON table1.t2_id = table2.id 

When I run EXPLAIN ANALYZE in PostgreSQL the IN() version seems to be 
slightly more efficient according to the planner (and real run times are 
more or less the same)
IN: Nested Loop  (cost=12.75..889.97 rows=35432 width=222) (actual 
time=42.200..42.209 rows=2 loops=1)
JOIN: Nested Loop  (cost=0.25..4386.37 rows=1000 width=226) (actual 
time=41.052..41.061 rows=2 loops=1)

-
Things I tried on the path to getting my answer:
-
I attempted to use a combination of a label and an alias with my function 
(modelled after this: 
http://docs.sqlalchemy.org/en/rel_0_7/orm/query.html?highlight=aliased#sqlalchemy.orm.aliased):

my_function = func.my_function(...args...).label(Table1.__tablename__)   
my_function_alias = aliased(Table1, alias=my_function, adapt_on_names=True)

but that failed miserably.  Using the labeled function in a regular core 
select resulted in an AttributeError exception, so I think that might have 
been part of the problem:

 print select('*', from_obj=[my_function])
Traceback (most recent call last):
  File stdin, line 1, in module
  File /Library/Python/2.7/site-packages/sqlalchemy/sql/expression.py, 
line 1790, in __str__
return unicode(self.compile()).encode('ascii', 'backslashreplace')
  File /Library/Python/2.7/site-packages/sqlalchemy/sql/expression.py, 
line 1778, in compile
return self._compiler(dialect, bind=bind, **kw)
  File /Library/Python/2.7/site-packages/sqlalchemy/sql/expression.py, 
line 1784, in _compiler
return dialect.statement_compiler(dialect, self, **kw)
  File /Library/Python/2.7/site-packages/sqlalchemy/sql/compiler.py, line 
277, in __init__
engine.Compiled.__init__(self, dialect, statement, **kwargs)
  File /Library/Python/2.7/site-packages/sqlalchemy/engine/base.py, line 
705, in __init__
self.string = self.process(self.statement)
  File /Library/Python/2.7/site-packages/sqlalchemy/engine/base.py, line 
724, in process
return obj._compiler_dispatch(self, **kwargs)
  File /Library/Python/2.7/site-packages/sqlalchemy/sql/visitors.py, line 
72, in _compiler_dispatch
return getter(visitor)(self, **kw)
  File /Library/Python/2.7/site-packages/sqlalchemy/sql/compiler.py, line 
873, in visit_select
froms = select._get_display_froms(existingfroms)
  File /Library/Python/2.7/site-packages/sqlalchemy/sql/expression.py, 
line 4807, in _get_display_froms
toremove = set(itertools.chain(*[f._hide_froms for f in froms]))
AttributeError: '_Label' object has no attribute '_hide_froms'


Using the aliased function would include the original table as well as the 
aliased functioned, and without a join condition it would just do a 
cartesian product:

 results = session.query(my_function_alias).first()
SELECT table1.id, table1.col1, table1.col2... FROM table1, (SELECT * FROM 
my_function(...args...))

So that didn't work either.  After doing this I realized that if I have to 
include the table and the function sub-select I might as well attempt it as 
an IN(), and that is what brought me to my final answer.

Thanks again for your suggestion Mike, it definitely put me on the right 
path to the solution.


On Thursday, September 20, 2012 7:10:52 PM UTC+2, Michael Bayer wrote:

 you can make a function act like a table by creating a select() out of it, 
 check out the fifth example at 
 http://docs.sqlalchemy.org/en/rel_0_7/core/tutorial.html#functions

 On Sep 20, 2012, at 1:09 PM, David McKeone wrote:

 Hi M,

 Is creating something in the database the only way to do it?  How would I 
 coerce the view's return type into my object?  How do I substitute the view 
 in the FROM part of my clause instead?


 On Thursday, September 20, 2012 5:52:28 PM UTC+2, A.M. wrote:


 On Sep 20, 2012, at 11:49 AM, David McKeone wrote: 

  I've googled around can't seem to find an answer to this, so hopefully 
 someone knows how to do it here. 
  
  I'm using PostgreSQL and I have a PL/PGSQL function that filters and 
 modifies a particular table based on a number of conditions and then 
 returns a set of rows as the result

[sqlalchemy] SELECT * FROM function() with declarative

2012-09-20 Thread David McKeone
I've googled around can't seem to find an answer to this, so hopefully 
someone knows how to do it here.

I'm using PostgreSQL and I have a PL/PGSQL function that filters and 
modifies a particular table based on a number of conditions and then 
returns a set of rows as the result.  This pattern has allowed the system 
to use the functions as if they were tables so that joins can still be done 
on the resulting values.

So instead of:

SELECT * FROM table1 INNER JOIN table2 ON table1.t2_id = table2.id

I do:

SELECT * FROM my_function( ...args... ) as table1 INNER JOIN table2 
ON table1.t2_id = table2.id

That part works ok in plain SQL (and as well in the system I'm converting 
from)

So now with SQLAlchemy I have my declarative definitions for those tables:

class Table1(Base):
   __tablename__ = 'table1'

   id = Column()
   t2_id = Column(ForeignKey())

   table2 = Relationship( ... )  # Join condition is specified explicitly

class Table2(Base);
   __tablename__ = 'table2'
 
   id = Column()

and I'm trying to figure out how I would execute a query that looks like 
this:

result = 
session.query(Table1).join(Table1.table2).options(contains_eager(Table1.table2))

but using a function to 'fake' Table1 instead.  So basically I'm attempting 
to get SQLAlchemy to treat the result of my function as if it was the 
normal Table1 object.  I've tried using select_from() to inject my call to 
func.my_function() but that doesn't seem to work and since what I'm doing 
seems like it might be tricky (or not portable across SQL) I thought I'd 
ask if it's even possible.

Thanks for any help!



-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/sqlalchemy/-/bYCl5PH0yNIJ.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] Portable date intervals?

2012-09-04 Thread David McKeone
Great, thanks Mike!  I only need to do PostgreSQL, but I will look into the 
@compiles decorator to make a more general solution.

.

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/sqlalchemy/-/JwSkrcDaPDwJ.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] SQLAlchemy with Flask -- hybrid models?

2012-08-23 Thread David McKeone


On Thursday, August 23, 2012 3:01:50 AM UTC+1, Michael Bayer wrote:


 On Aug 22, 2012, at 5:33 PM, David McKeone wrote: 

  I suppose I should be more clear.  This is really a long term question, 
 I was just looking for some kind of answer now because I don't want to code 
 myself into a corner in the short term.  Currently I can make requests 
 outside of a flask request context by using the app.test_request_context() 
 context manager, and it seems to do the right thing.   
  
  In the long term I'm looking for 2 (maybe 3) things that I already get 
 from Flask-SQLAlchemy: 
  1) Session teardown for every request (looks like that is done with a 
 call to session.remove() in the request teardown) 

 you can use the Session provided by flask-sqlalchemy, which has the nice 
 quality that it aligns itself with the current request. 

 He can make that feature more open-ended though.   I should be able to say 
 flask_sqlalchemy.request_scope(some_sessionmaker) to set that up with any 
 sessionmaker of my choosing. 


  2) Debug query tracking for use with Flask-DebugToolbar  (Plus 
 compatibility with other plug-ins that may expect Flask-SQLAlchemy) 

 the logic i see in flask-sqlalchemy related to debug tracking has no 
 connection to the db.Model class at all.   its just some connection 
 events which are ultimately established via the SQLAlchemy class.  Your 
 existing non-flask SQLA models will participate in the Session/Engine used 
 by Flask without impacting this functionaltiy. 


  3) The Model.query behaviour (it's nice, but I could live without it, 
 since its really just syntactic) 

 scoped_session has a query_property available, so you can pull that from 
 Flask's scoped_session using SQLAlchemy public APIs like this: 

 sa = SQLAlchemy(db) 

 # API: 
 http://docs.sqlalchemy.org/en/rel_0_7/orm/session.html#sqlalchemy.orm.scoping.ScopedSession.query_property
  
 Base.query = sa.session.query_property 


 or to get exactly flask's, which appears to add three methods get_or_404, 
 first_or_404, paginate: 

 Base.query = flask_sqlalchemy._QueryProperty(sa) 

  
  
  Didn't say this explicitly; for now I will do what you say and forge 
 ahead with things.  I think I see the path, but I'll make sure to let you 
 (the list) know if I run into trouble. 

 good luck ! 



Slugged it out today and got this working, hooray!  Thanks again for your 
help Mike (and for the time you probably put in to parse the 
Flask-SQLAlchemy code).  If you are at PyCon this year I WILL find you and 
I WILL buy you beer, unless you don't drink, in which case I WILL buy you 
soda or coffee.

I haven't done the Base.query part, and I may never do it (more below), but 
everything else works great and all my tests pass after switching to the 
new method.

The more I use the new system the more I wish I would have started with it. 
 Perhaps I can get it documented as an option, because I find it makes it 
far more clear where the models belong in the grand scheme of things.  Now, 
not everyone has 93 tables, a boat-load of relationships and requirements 
for doing things outside of HTTP like I do, so I can understand why it's 
been done the way that it's been done, but having to pass the db instance 
into all of my model definitions (and the resulting project structure 
issues I had) just wasn't worth it.  I've also found that having to use the 
session directly makes it far more clear which session is being used, and 
how.  Not to mention the benefits from being able to decouple my models 
from Flask completely.

So, in the name of Google search completeness,  here is the solution that I 
ultimately ended up with, adapted for the simple User model from above, for 
those like me who want/need it.  (It's quite simple, and I'm amazed that it 
hadn't occurred to me to try it like this)

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base

app =  Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:tmp/test.db'
db = SQLAlchemy(app)

Base = declarative_base()

class User(Base):
__tablename__ = 'users'

id = Column(Integer, primary_key=True)
name = Column(String(50), unique=True)
email = Column(String(120), unique=True)

def __init__(self, name=None, email=None):
self.name = name
self.email = email

def __repr__(self):
return 'User %r' % (self.name)

@app.before_first_request
def setup():
# Recreate database each time for demo
Base.metadata.drop_all(bind=db.engine)
Base.metadata.create_all(bind=db.engine)
db.session.add(User('Bob Jones', 'b...@gmail.com'))
db.session.add(User('Joe Quimby', 'e...@joes.com'))
db.session.commit()

@app.route('/')
def root():
users = db.session.query(User).all()
return ubr.join([u{0}: {1}.format(user.name, user.email) for user 
in users])

if __name__ == '__main__':
app.run('127.0.0.1', 5000

[sqlalchemy] SQLAlchemy with Flask -- hybrid models?

2012-08-22 Thread David McKeone
I've been using SQLAlchemy with Flask via the Flask extension 
Flask-SQLAlchemy. Everything works great so far, but I foresee a potential 
problem once I start to use my database model outside of Flask.  In the 
future I'd like to be able to use my models with non-Flask SQLAlchemy (a 
worker daemon process or with a PySide interface).  Well just use standard 
SQLAlchemy, you may say,  and fore-go the use of the extension.  That 
was my first thought, but sadly some useful extensions (notably 
Flask-DebugToolbar) seem to like using the extension version and it is nice 
to be able to have Flask manage the database sessions in the way that it 
does.  I'd like to not throw the baby out with the bath water.

I realize that this is somewhat specific to Flask, but is there a way that 
I could do both?  Can I create models with standard SQLAlchemy declarative 
and then somehow inject them into Flask-SQLAlchemy's way of doing things?

If it helps with the solution, I don't need to use any of the Model 
specific methods that Flask-SQLAlchemy provides (get_or_404, paginate, 
etc..) and I also specify a __tablename__ for all of my models, so I don't 
rely on Flask-SQLAlchemy generating that for me.

I took a look at the source of Flask-SQLAlchemy 
(https://github.com/mitsuhiko/flask-sqlalchemy/blob/master/flask_sqlalchemy.py) 
 and from what I can tell it seems that it's using Flask's signalling 
capabilities by customizing SQLAlchemy's session and mapper, but that is 
where my understanding ends (I'm still new to this whole stack, Python, 
Flask, SQLAlchemy) and I could use some pointers for how to proceed.


To visualize what I'm talking about, here are the two types of models. 
 A basic Flask-SQLAlchemy model looks like 
(http://packages.python.org/Flask-SQLAlchemy/quickstart.html#a-minimal-application):

from flask import Flask 
from flask.ext.sqlalchemy import SQLAlchemy 

app = Flask(__name__) 
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:tmp/test.db' 

db = SQLAlchemy(app) 

class User(db.Model): 
id = db.Column(db.Integer, primary_key=True) 
username = db.Column(db.String(80), unique=True) 
email = db.Column(db.String(120), unique=True) 

def __init__(self, username, email): 
 self.username = username 

   self.email = email 


def __repr__(self): 
return 'User %r' % self.username


Note the db.Model, db.Integer and db dot everything.

The plain declarative SQLAlchemy equivalent would be 
(http://flask.pocoo.org/docs/patterns/sqlalchemy/):


from sqlalchemy import Column Integer, String, create_engine 
from sqlalchemy.orm import scoped_session, sessionmaker 
from sqlalchemy.ext.declarative import declarative_base 

engine = create_engine('sqlite:tmp/test.db', convert_unicode=True) 
db_session = scoped_session(sessionmaker(autocommit=False, 
autoflush=False, bind=engine)) 
Base = declarative_base() 
Base.query = db_session.query_property() 


class User(Base): 
 __tablename__ = 'users' 

 id = Column(Integer, primary_key=True) 
 name = Column(String(50), unique=True) 
 email = Column(String(120), unique=True) 

 def __init__(self, name=None, email=None): 
 self.name = name 
 self.email = email 

 def __repr__(self): 
 return 'User %r' % (self.name)



Thanks for your help!

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/sqlalchemy/-/fyqvIAUBbcsJ.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] SQLAlchemy with Flask -- hybrid models?

2012-08-22 Thread David McKeone


On Wednesday, August 22, 2012 2:23:28 PM UTC+1, Simon King wrote:

 On Wed, Aug 22, 2012 at 12:51 PM, David McKeone 
 davidm...@gmail.comjavascript: 
 wrote: 
  I've been using SQLAlchemy with Flask via the Flask extension 
  Flask-SQLAlchemy. Everything works great so far, but I foresee a 
 potential 
  problem once I start to use my database model outside of Flask.  In the 
  future I'd like to be able to use my models with non-Flask SQLAlchemy (a 
  worker daemon process or with a PySide interface).  Well just use 
 standard 
  SQLAlchemy, you may say,  and fore-go the use of the extension.  That 
 was 
  my first thought, but sadly some useful extensions (notably 
  Flask-DebugToolbar) seem to like using the extension version and it is 
 nice 
  to be able to have Flask manage the database sessions in the way that it 
  does.  I'd like to not throw the baby out with the bath water. 
  
  I realize that this is somewhat specific to Flask, but is there a way 
 that I 
  could do both?  Can I create models with standard SQLAlchemy declarative 
 and 
  then somehow inject them into Flask-SQLAlchemy's way of doing things? 
  
  If it helps with the solution, I don't need to use any of the Model 
 specific 
  methods that Flask-SQLAlchemy provides (get_or_404, paginate, etc..) and 
 I 
  also specify a __tablename__ for all of my models, so I don't rely on 
  Flask-SQLAlchemy generating that for me. 
  
  I took a look at the source of Flask-SQLAlchemy 
  (
 https://github.com/mitsuhiko/flask-sqlalchemy/blob/master/flask_sqlalchemy.py)
  

  and from what I can tell it seems that it's using Flask's signalling 
  capabilities by customizing SQLAlchemy's session and mapper, but that is 
  where my understanding ends (I'm still new to this whole stack, Python, 
  Flask, SQLAlchemy) and I could use some pointers for how to proceed. 
  
  
  To visualize what I'm talking about, here are the two types of models. 
  A 
  basic Flask-SQLAlchemy model looks like 
  (
 http://packages.python.org/Flask-SQLAlchemy/quickstart.html#a-minimal-application):
  

  
  from flask import Flask 
  from flask.ext.sqlalchemy import SQLAlchemy 
  
  app = Flask(__name__) 
  app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:tmp/test.db' 
  
  db = SQLAlchemy(app) 
  
  class User(db.Model): 
  id = db.Column(db.Integer, primary_key=True) 
  username = db.Column(db.String(80), unique=True) 
  email = db.Column(db.String(120), unique=True) 
  
  def __init__(self, username, email): 
   self.username = username 
  
 self.email = email 
  
  
  def __repr__(self): 
  return 'User %r' % self.username 
  
  
  Note the db.Model, db.Integer and db dot everything. 
  
  The plain declarative SQLAlchemy equivalent would be 
  (http://flask.pocoo.org/docs/patterns/sqlalchemy/): 
  
  
  from sqlalchemy import Column Integer, String, create_engine 
  from sqlalchemy.orm import scoped_session, sessionmaker 
  from sqlalchemy.ext.declarative import declarative_base 
  
  engine = create_engine('sqlite:tmp/test.db', convert_unicode=True) 
  db_session = scoped_session(sessionmaker(autocommit=False, 
 autoflush=False, 
  bind=engine)) 
  Base = declarative_base() 
  Base.query = db_session.query_property() 
  
  
  class User(Base): 
   __tablename__ = 'users' 
  
   id = Column(Integer, primary_key=True) 
   name = Column(String(50), unique=True) 
   email = Column(String(120), unique=True) 
  
   def __init__(self, name=None, email=None): 
   self.name = name 
   self.email = email 
  
   def __repr__(self): 
   return 'User %r' % (self.name) 
  

 From a very quick read of the Flask-SQLAlchemy docs, I would have 
 thought you could just use your flask-based classes in non-Flask-based 
 apps without any issue. The quickstart guide that you referenced above 
 illustrates a command-line session using them, so there's no reason 
 why you couldn't do the same in a worker process. 

 Have you already tried it and found that it doesn't work? 

 Simon 



Perhaps I've missed the important bit, but my understanding is that there 
are two ways to do it:

1) Use SQLAlchemy with manual session control (
http://flask.pocoo.org/docs/patterns/sqlalchemy/)
2) Use SQLAlchemy with the Flask-SQLAlchemy extension which does session 
control for you, but requires you to use it's own declarative base class, 
db.Model  (
http://packages.python.org/Flask-SQLAlchemy/quickstart.html#a-minimal-application
)

The problem is that other extensions give you additional features if you 
use solution #2, but not if you use solution #1, because solution #1 
implies that you are going to do everything yourself manually.  I'm fine 
with the way solution #2 handles the sessions and everything else, I just 
want to be able to use my own declarative base so that the models are 
more-or-less independent of the app that they are being used in.

-- 
You received this message

Re: [sqlalchemy] SQLAlchemy with Flask -- hybrid models?

2012-08-22 Thread David McKeone


On Wednesday, August 22, 2012 2:33:01 PM UTC+1, David McKeone wrote:



 On Wednesday, August 22, 2012 2:23:28 PM UTC+1, Simon King wrote:

 On Wed, Aug 22, 2012 at 12:51 PM, David McKeone davidm...@gmail.com 
 wrote: 
  I've been using SQLAlchemy with Flask via the Flask extension 
  Flask-SQLAlchemy. Everything works great so far, but I foresee a 
 potential 
  problem once I start to use my database model outside of Flask.  In the 
  future I'd like to be able to use my models with non-Flask SQLAlchemy 
 (a 
  worker daemon process or with a PySide interface).  Well just use 
 standard 
  SQLAlchemy, you may say,  and fore-go the use of the extension. 
  That was 
  my first thought, but sadly some useful extensions (notably 
  Flask-DebugToolbar) seem to like using the extension version and it is 
 nice 
  to be able to have Flask manage the database sessions in the way that 
 it 
  does.  I'd like to not throw the baby out with the bath water. 
  
  I realize that this is somewhat specific to Flask, but is there a way 
 that I 
  could do both?  Can I create models with standard SQLAlchemy 
 declarative and 
  then somehow inject them into Flask-SQLAlchemy's way of doing things? 
  
  If it helps with the solution, I don't need to use any of the Model 
 specific 
  methods that Flask-SQLAlchemy provides (get_or_404, paginate, etc..) 
 and I 
  also specify a __tablename__ for all of my models, so I don't rely on 
  Flask-SQLAlchemy generating that for me. 
  
  I took a look at the source of Flask-SQLAlchemy 
  (
 https://github.com/mitsuhiko/flask-sqlalchemy/blob/master/flask_sqlalchemy.py)
  

  and from what I can tell it seems that it's using Flask's signalling 
  capabilities by customizing SQLAlchemy's session and mapper, but that 
 is 
  where my understanding ends (I'm still new to this whole stack, Python, 
  Flask, SQLAlchemy) and I could use some pointers for how to proceed. 
  
  
  To visualize what I'm talking about, here are the two types of models. 
  A 
  basic Flask-SQLAlchemy model looks like 
  (
 http://packages.python.org/Flask-SQLAlchemy/quickstart.html#a-minimal-application):
  

  
  from flask import Flask 
  from flask.ext.sqlalchemy import SQLAlchemy 
  
  app = Flask(__name__) 
  app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:tmp/test.db' 
  
  db = SQLAlchemy(app) 
  
  class User(db.Model): 
  id = db.Column(db.Integer, primary_key=True) 
  username = db.Column(db.String(80), unique=True) 
  email = db.Column(db.String(120), unique=True) 
  
  def __init__(self, username, email): 
   self.username = username 
  
 self.email = email 
  
  
  def __repr__(self): 
  return 'User %r' % self.username 
  
  
  Note the db.Model, db.Integer and db dot everything. 
  
  The plain declarative SQLAlchemy equivalent would be 
  (http://flask.pocoo.org/docs/patterns/sqlalchemy/): 
  
  
  from sqlalchemy import Column Integer, String, create_engine 
  from sqlalchemy.orm import scoped_session, sessionmaker 
  from sqlalchemy.ext.declarative import declarative_base 
  
  engine = create_engine('sqlite:tmp/test.db', convert_unicode=True) 
  db_session = scoped_session(sessionmaker(autocommit=False, 
 autoflush=False, 
  bind=engine)) 
  Base = declarative_base() 
  Base.query = db_session.query_property() 
  
  
  class User(Base): 
   __tablename__ = 'users' 
  
   id = Column(Integer, primary_key=True) 
   name = Column(String(50), unique=True) 
   email = Column(String(120), unique=True) 
  
   def __init__(self, name=None, email=None): 
   self.name = name 
   self.email = email 
  
   def __repr__(self): 
   return 'User %r' % (self.name) 
  

 From a very quick read of the Flask-SQLAlchemy docs, I would have 
 thought you could just use your flask-based classes in non-Flask-based 
 apps without any issue. The quickstart guide that you referenced above 
 illustrates a command-line session using them, so there's no reason 
 why you couldn't do the same in a worker process. 

 Have you already tried it and found that it doesn't work? 

 Simon 



 Perhaps I've missed the important bit, but my understanding is that there 
 are two ways to do it:

 1) Use SQLAlchemy with manual session control (
 http://flask.pocoo.org/docs/patterns/sqlalchemy/)
 2) Use SQLAlchemy with the Flask-SQLAlchemy extension which does session 
 control for you, but requires you to use it's own declarative base class, 
 db.Model  (
 http://packages.python.org/Flask-SQLAlchemy/quickstart.html#a-minimal-application
 )

 The problem is that other extensions give you additional features if you 
 use solution #2, but not if you use solution #1, because solution #1 
 implies that you are going to do everything yourself manually.  I'm fine 
 with the way solution #2 handles the sessions and everything else, I just 
 want to be able to use my own declarative base so that the models are 
 more-or-less

Re: [sqlalchemy] SQLAlchemy with Flask -- hybrid models?

2012-08-22 Thread David McKeone
On Wednesday, August 22, 2012 3:12:02 PM UTC+1, Simon King wrote:

 On Wed, Aug 22, 2012 at 2:44 PM, David McKeone 
 davidm...@gmail.comjavascript: 
 wrote: 
  
  
  On Wednesday, August 22, 2012 2:33:01 PM UTC+1, David McKeone wrote: 
  
  
  
  On Wednesday, August 22, 2012 2:23:28 PM UTC+1, Simon King wrote: 
  
  On Wed, Aug 22, 2012 at 12:51 PM, David McKeone davidm...@gmail.com 
  wrote: 
   I've been using SQLAlchemy with Flask via the Flask extension 
   Flask-SQLAlchemy. Everything works great so far, but I foresee a 
   potential 
   problem once I start to use my database model outside of Flask.  In 
 the 
   future I'd like to be able to use my models with non-Flask 
 SQLAlchemy 
   (a 
   worker daemon process or with a PySide interface).  Well just use 
   standard 
   SQLAlchemy, you may say,  and fore-go the use of the extension. 
   That was 
   my first thought, but sadly some useful extensions (notably 
   Flask-DebugToolbar) seem to like using the extension version and it 
 is 
   nice 
   to be able to have Flask manage the database sessions in the way 
 that 
   it 
   does.  I'd like to not throw the baby out with the bath water. 
   
   I realize that this is somewhat specific to Flask, but is there a 
 way 
   that I 
   could do both?  Can I create models with standard SQLAlchemy 
   declarative and 
   then somehow inject them into Flask-SQLAlchemy's way of doing 
 things? 
   
   If it helps with the solution, I don't need to use any of the Model 
   specific 
   methods that Flask-SQLAlchemy provides (get_or_404, paginate, etc..) 
   and I 
   also specify a __tablename__ for all of my models, so I don't rely 
 on 
   Flask-SQLAlchemy generating that for me. 
   
   I took a look at the source of Flask-SQLAlchemy 
   
   (
 https://github.com/mitsuhiko/flask-sqlalchemy/blob/master/flask_sqlalchemy.py)
  

   and from what I can tell it seems that it's using Flask's signalling 
   capabilities by customizing SQLAlchemy's session and mapper, but 
 that 
   is 
   where my understanding ends (I'm still new to this whole stack, 
 Python, 
   Flask, SQLAlchemy) and I could use some pointers for how to proceed. 
   
   
   To visualize what I'm talking about, here are the two types of 
 models. 
   A 
   basic Flask-SQLAlchemy model looks like 
   
   (
 http://packages.python.org/Flask-SQLAlchemy/quickstart.html#a-minimal-application):
  

   
   from flask import Flask 
   from flask.ext.sqlalchemy import SQLAlchemy 
   
   app = Flask(__name__) 
   app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:tmp/test.db' 
   
   db = SQLAlchemy(app) 
   
   class User(db.Model): 
   id = db.Column(db.Integer, primary_key=True) 
   username = db.Column(db.String(80), unique=True) 
   email = db.Column(db.String(120), unique=True) 
   
   def __init__(self, username, email): 
self.username = username 
   
  self.email = email 
   
   
   def __repr__(self): 
   return 'User %r' % self.username 
   
   
   Note the db.Model, db.Integer and db dot everything. 
   
   The plain declarative SQLAlchemy equivalent would be 
   (http://flask.pocoo.org/docs/patterns/sqlalchemy/): 
   
   
   from sqlalchemy import Column Integer, String, create_engine 
   from sqlalchemy.orm import scoped_session, sessionmaker 
   from sqlalchemy.ext.declarative import declarative_base 
   
   engine = create_engine('sqlite:tmp/test.db', 
 convert_unicode=True) 
   db_session = scoped_session(sessionmaker(autocommit=False, 
   autoflush=False, 
   bind=engine)) 
   Base = declarative_base() 
   Base.query = db_session.query_property() 
   
   
   class User(Base): 
__tablename__ = 'users' 
   
id = Column(Integer, primary_key=True) 
name = Column(String(50), unique=True) 
email = Column(String(120), unique=True) 
   
def __init__(self, name=None, email=None): 
self.name = name 
self.email = email 
   
def __repr__(self): 
return 'User %r' % (self.name) 
   
  
  From a very quick read of the Flask-SQLAlchemy docs, I would have 
  thought you could just use your flask-based classes in non-Flask-based 
  apps without any issue. The quickstart guide that you referenced above 
  illustrates a command-line session using them, so there's no reason 
  why you couldn't do the same in a worker process. 
  
  Have you already tried it and found that it doesn't work? 
  
  Simon 
  
  
  
  Perhaps I've missed the important bit, but my understanding is that 
 there 
  are two ways to do it: 
  
  1) Use SQLAlchemy with manual session control 
  (http://flask.pocoo.org/docs/patterns/sqlalchemy/) 
  2) Use SQLAlchemy with the Flask-SQLAlchemy extension which does 
 session 
  control for you, but requires you to use it's own declarative base 
 class, 
  db.Model 
  (
 http://packages.python.org/Flask-SQLAlchemy/quickstart.html#a-minimal-application)
  

  
  The problem

Re: [sqlalchemy] SQLAlchemy with Flask -- hybrid models?

2012-08-22 Thread David McKeone


On Wednesday, August 22, 2012 3:12:02 PM UTC+1, Simon King wrote:

 On Wed, Aug 22, 2012 at 2:44 PM, David McKeone 
 davidm...@gmail.comjavascript: 
 wrote: 
  
  
  On Wednesday, August 22, 2012 2:33:01 PM UTC+1, David McKeone wrote: 
  
  
  
  On Wednesday, August 22, 2012 2:23:28 PM UTC+1, Simon King wrote: 
  
  On Wed, Aug 22, 2012 at 12:51 PM, David McKeone davidm...@gmail.com 
  wrote: 
   I've been using SQLAlchemy with Flask via the Flask extension 
   Flask-SQLAlchemy. Everything works great so far, but I foresee a 
   potential 
   problem once I start to use my database model outside of Flask.  In 
 the 
   future I'd like to be able to use my models with non-Flask 
 SQLAlchemy 
   (a 
   worker daemon process or with a PySide interface).  Well just use 
   standard 
   SQLAlchemy, you may say,  and fore-go the use of the extension. 
   That was 
   my first thought, but sadly some useful extensions (notably 
   Flask-DebugToolbar) seem to like using the extension version and it 
 is 
   nice 
   to be able to have Flask manage the database sessions in the way 
 that 
   it 
   does.  I'd like to not throw the baby out with the bath water. 
   
   I realize that this is somewhat specific to Flask, but is there a 
 way 
   that I 
   could do both?  Can I create models with standard SQLAlchemy 
   declarative and 
   then somehow inject them into Flask-SQLAlchemy's way of doing 
 things? 
   
   If it helps with the solution, I don't need to use any of the Model 
   specific 
   methods that Flask-SQLAlchemy provides (get_or_404, paginate, etc..) 
   and I 
   also specify a __tablename__ for all of my models, so I don't rely 
 on 
   Flask-SQLAlchemy generating that for me. 
   
   I took a look at the source of Flask-SQLAlchemy 
   
   (
 https://github.com/mitsuhiko/flask-sqlalchemy/blob/master/flask_sqlalchemy.py)
  

   and from what I can tell it seems that it's using Flask's signalling 
   capabilities by customizing SQLAlchemy's session and mapper, but 
 that 
   is 
   where my understanding ends (I'm still new to this whole stack, 
 Python, 
   Flask, SQLAlchemy) and I could use some pointers for how to proceed. 
   
   
   To visualize what I'm talking about, here are the two types of 
 models. 
   A 
   basic Flask-SQLAlchemy model looks like 
   
   (
 http://packages.python.org/Flask-SQLAlchemy/quickstart.html#a-minimal-application):
  

   
   from flask import Flask 
   from flask.ext.sqlalchemy import SQLAlchemy 
   
   app = Flask(__name__) 
   app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:tmp/test.db' 
   
   db = SQLAlchemy(app) 
   
   class User(db.Model): 
   id = db.Column(db.Integer, primary_key=True) 
   username = db.Column(db.String(80), unique=True) 
   email = db.Column(db.String(120), unique=True) 
   
   def __init__(self, username, email): 
self.username = username 
   
  self.email = email 
   
   
   def __repr__(self): 
   return 'User %r' % self.username 
   
   
   Note the db.Model, db.Integer and db dot everything. 
   
   The plain declarative SQLAlchemy equivalent would be 
   (http://flask.pocoo.org/docs/patterns/sqlalchemy/): 
   
   
   from sqlalchemy import Column Integer, String, create_engine 
   from sqlalchemy.orm import scoped_session, sessionmaker 
   from sqlalchemy.ext.declarative import declarative_base 
   
   engine = create_engine('sqlite:tmp/test.db', 
 convert_unicode=True) 
   db_session = scoped_session(sessionmaker(autocommit=False, 
   autoflush=False, 
   bind=engine)) 
   Base = declarative_base() 
   Base.query = db_session.query_property() 
   
   
   class User(Base): 
__tablename__ = 'users' 
   
id = Column(Integer, primary_key=True) 
name = Column(String(50), unique=True) 
email = Column(String(120), unique=True) 
   
def __init__(self, name=None, email=None): 
self.name = name 
self.email = email 
   
def __repr__(self): 
return 'User %r' % (self.name) 
   
  
  From a very quick read of the Flask-SQLAlchemy docs, I would have 
  thought you could just use your flask-based classes in non-Flask-based 
  apps without any issue. The quickstart guide that you referenced above 
  illustrates a command-line session using them, so there's no reason 
  why you couldn't do the same in a worker process. 
  
  Have you already tried it and found that it doesn't work? 
  
  Simon 
  
  
  
  Perhaps I've missed the important bit, but my understanding is that 
 there 
  are two ways to do it: 
  
  1) Use SQLAlchemy with manual session control 
  (http://flask.pocoo.org/docs/patterns/sqlalchemy/) 
  2) Use SQLAlchemy with the Flask-SQLAlchemy extension which does 
 session 
  control for you, but requires you to use it's own declarative base 
 class, 
  db.Model 
  (
 http://packages.python.org/Flask-SQLAlchemy/quickstart.html#a-minimal-application)
  

  
  The problem

Re: [sqlalchemy] SQLAlchemy with Flask -- hybrid models?

2012-08-22 Thread David McKeone


On Wednesday, August 22, 2012 5:36:22 PM UTC+1, Michael Bayer wrote:


 On Aug 22, 2012, at 7:51 AM, David McKeone wrote:

 I've been using SQLAlchemy with Flask via the Flask extension 
 Flask-SQLAlchemy. Everything works great so far, but I foresee a potential 
 problem once I start to use my database model outside of Flask.  In the 
 future I'd like to be able to use my models with non-Flask SQLAlchemy (a 
 worker daemon process or with a PySide interface).  Well just use standard 
 SQLAlchemy, you may say,  and fore-go the use of the extension.  That 
 was my first thought, but sadly some useful extensions (notably 
 Flask-DebugToolbar) seem to like using the extension version and it is nice 
 to be able to have Flask manage the database sessions in the way that it 
 does.  I'd like to not throw the baby out with the bath water.

 I realize that this is somewhat specific to Flask, but is there a way that 
 I could do both?  Can I create models with standard SQLAlchemy declarative 
 and then somehow inject them into Flask-SQLAlchemy's way of doing things?


 If it helps with the solution, I don't need to use any of the Model 
 specific methods that Flask-SQLAlchemy provides (get_or_404, paginate, 
 etc..) and I also specify a __tablename__ for all of my models, so I don't 
 rely on Flask-SQLAlchemy generating that for me.

 I took a look at the source of Flask-SQLAlchemy (
 https://github.com/mitsuhiko/flask-sqlalchemy/blob/master/flask_sqlalchemy.py)
  
  and from what I can tell it seems that it's using Flask's signalling 
 capabilities by customizing SQLAlchemy's session and mapper, but that is 
 where my understanding ends (I'm still new to this whole stack, Python, 
 Flask, SQLAlchemy) and I could use some pointers for how to proceed.



 There's no reason I can see in the source that flask-sqlalchemy would get 
 in the way of entirely plain SQLAlchemy mapped objects.   At the end of the 
 day, a class that extends Flask's db.model is just a mapped class, just 
 like a non-flask class.  Both kinds of classes are freely usable with any 
 SQLAlchemy Session, including the Session that Flask-SQLA provides.It's 
 important to note the distinction between mapper configuration, which has 
 to do with class structure, and session configuration, which only deals 
 with instances of objects.  These two processes work together at a core 
 level that various extensions only ride on top of, unless those extensions 
 define additional dependencies above that level.   Flask-sqlalchemy appears 
 only to define one very trivial such dependency which is some coordination 
 to enable the before_models_committed and models_committed hooks, which 
 themselves are just for end-user convenience (
 http://packages.python.org/Flask-SQLAlchemy/signals.html).   

 The Flask-SQLA approach is really just assigning event listeners to 
 sessions and mappers.   It's doing so in a way that is a bit brittle, but 
 also this system precedes SQLAlchemy's 0.7 event model.   Armin's immediate 
 goal with flask-sqlalchemy is to migrate the extension to use the new event 
 model, which would actually remove the need for the styles of registration 
 I see here as the new system allows registration of event listeners on all 
 sessions/mappers non-intrusively.

 There's also a custom Query class in use here, though it doesn't seem to 
 be consistently integrated with the Session, but using custom Query classes 
 like this as well as adding the MyClass.query hook is a widely used 
 pattern.

 So if you were to use plain SQLAlchemy models with flask-SQLA out of the 
 box, these particular events wouldn't fire off as much, unless you also set 
 up the flask_sqlalchemy._SignalTrackingMapperExtension with your normal 
 mappers.   

 I think if you just tried using regular models with flask models, and 
 didn't rely on those two particular signals, you'd see everything pretty 
 much works without any issue.


Thanks for your great response Mike.  

Forgive my ignorance, but I don't understand enough of the underpinnings to 
get my first steps out of this (the downside of starting with something 
that gives you stuff for free, I suppose).  I'm definitely going to walk 
through what you've said and reference it against the documentation, but 
while your mind is fresh on the topic, I was wondering if you could just 
clarify how I might convert a standard model object into a flask-sqlalchemy 
model object.

Using the two examples above, would I just take my User(Base) class and 
then assign it property out of the Flask db properties?  Something like: 

User.session = db.session()  
User.engine = db.engine()

I know those properties don't actually exist on User, but is that the kind 
of thing I should be looking to do?  Move certain pieces into all of the 
models?  or is there something higher level going on that will do this for 
me in some way? something else?

... but also this system precedes SQLAlchemy's 0.7 event model.   Armin's

Re: [sqlalchemy] SQLAlchemy with Flask -- hybrid models?

2012-08-22 Thread David McKeone


On Wednesday, August 22, 2012 9:03:55 PM UTC+1, Michael Bayer wrote:


 On Aug 22, 2012, at 3:51 PM, David McKeone wrote:


  I was wondering if you could just clarify how I might convert a standard 
 model object into a flask-sqlalchemy model object.


 why do you need to do this ?What flask-sqlalchemy-specific features 
 would you hope for the model objects to have ?   There's pretty much two I 
 can see - one is the MyModel.query attribute, and the other are the events. 
  Neither are necessary, though you might want the usage of one or the 
 other.   Otherwise no conversion is needed.


 Using the two examples above, would I just take my User(Base) class and 
 then assign it property out of the Flask db properties?  Something like: 

 User.session = db.session()  
 User.engine = db.engine()

 I know those properties don't actually exist on User, but is that the kind 
 of thing I should be looking to do?  Move certain pieces into all of the 
 models?  or is there something higher level going on that will do this for 
 me in some way? something else?


 I don't see why engine or session would be stuck onto the model class like 
 that,  I don't see that usage here: 
 http://packages.python.org/Flask-SQLAlchemy/quickstart.html#a-minimal-application.
  
  Just the query attribute.  User.query.all().  This is equivalent to 
 session.query(User).all().

 The User.session / User.engine pattern suggests that a model class acts 
 as a registry for how to get at a live database connection.  That pattern 
 is one that SQLAlchemy specifically discourages.   In the Flask docs, 
 you'll see that the handle to the state of a transaction is db.session. 
  The objects like instances of User are then contained within that.


  This seems like it would be a really good way to accomplish what I'm 
 looking for and to move things forward as well.  Once I read up on the 
 requisite knowledge I may end up making an attempt at making this over the 
 next little while.  I had a drink with Armin last week and I'm not sure if 
 his current stuff points him in this direction (of course you'd have to ask 
 him for the real answer on that), but I certainly have a vested interest, 
 so maybe I can do some of the grunt work.


 its really quite a small amount of effort.   I think for now the strategy 
 on your end should be to forge ahead with what's there, and if there's some 
 very specific thing that doesn't work as you expect, I can show you how to 
 get the behavior you're looking for.



I suppose I should be more clear.  This is really a long term question, I 
was just looking for some kind of answer now because I don't want to code 
myself into a corner in the short term.  Currently I can make requests 
outside of a flask request context by using the app.test_request_context() 
context manager, and it seems to do the right thing.   

In the long term I'm looking for 2 (maybe 3) things that I already get from 
Flask-SQLAlchemy:
1) Session teardown for every request (looks like that is done with a call 
to session.remove() in the request teardown)
2) Debug query tracking for use with Flask-DebugToolbar  (Plus 
compatibility with other plug-ins that may expect Flask-SQLAlchemy)

- This is really the difficult one.  In this case I think it just needs an 
attribute on the Flask app called sqlalchemy_queries which contains a tuple 
of queries.  This is where I was thinking it may be better to assist with 
updating the plugin to just play nice with SQLAlchemy's default behaviours. 
 Maybe I'm wrong?

3) The Model.query behaviour (it's nice, but I could live without it, since 
its really just syntactic)

I think it'll make my code simpler/better for two reasons:
1) My models will be SQLAlchemy, not a Flask specific dialect with db dot 
everywhere.  This will make the SQLAlchemy documentation more obvious to 
programmers that use the code.
2) The db.Model method seems to make it very easy to create circular import 
errors (as seen in this issue: 
https://github.com/mitsuhiko/flask-sqlalchemy/issues/97 and experienced by 
myself).  It would be really nice if I could isolate the models and model 
mapping behaviours from the rest of the application to avoid that kind of 
thing.

The User.session / User.engine pattern suggests that a model class acts 
 as a registry for how to get at a live database connection.  That pattern 
 is one that SQLAlchemy specifically discourages.   In the Flask docs, 
 you'll see that the handle to the state of a transaction is db.session. 
  The objects like instances of User are then contained within that.


This was really just my lack of understanding of how the database 
connection is connected to the models, rather than stating how I wanted it 
to be done.  Thinking about it now, and reading your comment, I realize 
that sessions are connected to the models when they are passed in, like in 
session.query(User).first(), and Model.query is really just a class 
instance that holds onto the session

Re: [sqlalchemy] SQLAlchemy with Flask -- hybrid models?

2012-08-22 Thread David McKeone


On Wednesday, August 22, 2012 10:21:59 PM UTC+1, David McKeone wrote:



 On Wednesday, August 22, 2012 9:03:55 PM UTC+1, Michael Bayer wrote:


 On Aug 22, 2012, at 3:51 PM, David McKeone wrote:


  I was wondering if you could just clarify how I might convert a standard 
 model object into a flask-sqlalchemy model object.


 why do you need to do this ?What flask-sqlalchemy-specific features 
 would you hope for the model objects to have ?   There's pretty much two I 
 can see - one is the MyModel.query attribute, and the other are the events. 
  Neither are necessary, though you might want the usage of one or the 
 other.   Otherwise no conversion is needed.


 Using the two examples above, would I just take my User(Base) class and 
 then assign it property out of the Flask db properties?  Something like: 

 User.session = db.session()  
 User.engine = db.engine()

 I know those properties don't actually exist on User, but is that the 
 kind of thing I should be looking to do?  Move certain pieces into all of 
 the models?  or is there something higher level going on that will do this 
 for me in some way? something else?


 I don't see why engine or session would be stuck onto the model class 
 like that,  I don't see that usage here: 
 http://packages.python.org/Flask-SQLAlchemy/quickstart.html#a-minimal-application.
  
  Just the query attribute.  User.query.all().  This is equivalent to 
 session.query(User).all().

 The User.session / User.engine pattern suggests that a model class acts 
 as a registry for how to get at a live database connection.  That pattern 
 is one that SQLAlchemy specifically discourages.   In the Flask docs, 
 you'll see that the handle to the state of a transaction is db.session. 
  The objects like instances of User are then contained within that.


  This seems like it would be a really good way to accomplish what I'm 
 looking for and to move things forward as well.  Once I read up on the 
 requisite knowledge I may end up making an attempt at making this over the 
 next little while.  I had a drink with Armin last week and I'm not sure if 
 his current stuff points him in this direction (of course you'd have to ask 
 him for the real answer on that), but I certainly have a vested interest, 
 so maybe I can do some of the grunt work.


 its really quite a small amount of effort.   I think for now the strategy 
 on your end should be to forge ahead with what's there, and if there's some 
 very specific thing that doesn't work as you expect, I can show you how to 
 get the behavior you're looking for.



 I suppose I should be more clear.  This is really a long term question, I 
 was just looking for some kind of answer now because I don't want to code 
 myself into a corner in the short term.  Currently I can make requests 
 outside of a flask request context by using the app.test_request_context() 
 context manager, and it seems to do the right thing.   

 In the long term I'm looking for 2 (maybe 3) things that I already get 
 from Flask-SQLAlchemy:
 1) Session teardown for every request (looks like that is done with a call 
 to session.remove() in the request teardown)
 2) Debug query tracking for use with Flask-DebugToolbar  (Plus 
 compatibility with other plug-ins that may expect Flask-SQLAlchemy)

 - This is really the difficult one.  In this case I think it just needs an 
 attribute on the Flask app called sqlalchemy_queries which contains a tuple 
 of queries.  This is where I was thinking it may be better to assist with 
 updating the plugin to just play nice with SQLAlchemy's default behaviours. 
  Maybe I'm wrong?

 3) The Model.query behaviour (it's nice, but I could live without it, 
 since its really just syntactic)

 I think it'll make my code simpler/better for two reasons:
 1) My models will be SQLAlchemy, not a Flask specific dialect with db 
 dot everywhere.  This will make the SQLAlchemy documentation more obvious 
 to programmers that use the code.
 2) The db.Model method seems to make it very easy to create circular 
 import errors (as seen in this issue: 
 https://github.com/mitsuhiko/flask-sqlalchemy/issues/97 and experienced 
 by myself).  It would be really nice if I could isolate the models and 
 model mapping behaviours from the rest of the application to avoid that 
 kind of thing.

 The User.session / User.engine pattern suggests that a model class acts 
 as a registry for how to get at a live database connection.  That pattern 
 is one that SQLAlchemy specifically discourages.   In the Flask docs, 
 you'll see that the handle to the state of a transaction is db.session. 
  The objects like instances of User are then contained within that.


 This was really just my lack of understanding of how the database 
 connection is connected to the models, rather than stating how I wanted it 
 to be done.  Thinking about it now, and reading your comment, I realize 
 that sessions are connected to the models when they are passed in, like

[sqlalchemy] Declarative and deferred

2012-08-11 Thread David McKeone
Short:
---
Is there a way to backfill multiple deferred columns in a declarative object 
result instance in a dynamic way when groups can't be predicted in the model?


Long:

First, let me just say thanks for SQLAlchemy.  This is my first post to this 
list and after working with it for quite a while I've found it to be an 
excellent tool for working with the database.  My previous work (non-Python) 
was done with a database abstraction layer that was more relational and less 
object-oriented and I've found SQLAlchemy to be amazing for letting me have my 
cake (objects) and eat it too (hand-crafted sql optimizations).

Alright, so a few caveats for background:
1) I'm fairly new to Python (~4 months), but not to programming (~10 years)
2) This is the first time I've used an ORM, so my question may be more about 
the object-relational mismatch handling, rather than SQLAlchemy directly. 
3) I'm using SQLAlchemy with Flask's plug-in flask-sqlalchemy.  That may not 
have much do with my question, but just in case there is some subtle difference 
between declarative's base model and Flask's db.Model
4) The current project is to use Flask and SQLAlchemy to create a web site with 
an existing database in a deployed client-server application (96 Tables, can be 
anywhere between ~200MB and 30GB)
5) Assumptions abound... this is a fairly complicated/specific case (I think) 
so there may be underlying assumptions about how I'm doing things that are 
incorrect.  If I'm wrong in those underlying assumptions, then feel free to 
challenge them.
6) SQLAlchemy 0.7.8

Cool.

So, I see that using declarative objects has a quite a few advantages;  you can 
easily add attributes(columns, relationships, etc...), validators, and methods 
-- all great stuff for keeping things logically grouped. Then when you get to 
performance optimizations there is a significant benefit with larger models to 
not fetch all the columns for every request (this is a web app after all, so 
lower response times are a goal).  Great, so deferred looks like the ticket to 
be able to handle this particular mis-match in a good enough way.  I can defer 
any non-essential columns and if I need one or two other columns down the line 
then they'll be lazy-loaded as required. 

Contrived example:

class User(db.Model, HelperMixin):
__tablename__ =  'user'

id = db.Column(db.Integer, primary_key=True)
password = db.Column(db.String)
type = db.Column(db.Integer)
first_name = db.Column(db.String)
last_name = db.Column(db.String)
title = db.Column(db.String)
birthday = db.Column(db.Date)
height = db.Column(db.Numeric)
width = db.Column(db.Numeric)
# etc...

   def is_valid(self, check_password):
  # check password in a horribly insecure, but easy way
  return True if check_password == self.password else False

So with this model I want to validate a users password on login, but not load 
all the other unnecessary stuff, because login probably doesn't need all the 
rest of those columns.  Because I also want to keep things simple on the model, 
I don't use deferred directly, but rather I created a couple helper methods in 
a mixin.   (Note that other parts of the application may need more columns or 
less columns or different columns, depending on context, so putting deferreds 
directly in the model would also be impractical)

The mixin looks like this:

from sqlalchemy.orm import defer
from sqlalchemy.orm.properties import ColumnProperty
from sqlalchemy.orm.util import class_mapper

class HelperMixin(object):

@classmethod
def itercolumns(cls):
for prop in class_mapper(cls).iterate_properties:
if isinstance(prop, ColumnProperty):
yield prop.key

@classmethod
def get_deferred_except(cls, *attributes):
attribute_set = set(attributes)

ret = list()
for name in cls.itercolumns():
if name not in attribute_set:
ret.append(defer(name))

return ret

so with this helper I can context sensitively build up a result object with 
just the stuff I need (but without losing the benefits of the associated 
methods):

deferred = User.get_deferred_except('id', 'password') # Get list of defer() 
instances for all columns, but those specified
user = User.query.options(*deferred).first()

# SQL Emitted -- SELECT id, password FROM user

if user.is_valid(the_password):
# Valid stuff
else:
# Invalid stuff

Ok, well that worked great, but now I need to get the patrons name for some 
runtime specific reason.  So I do this:

full_name =  .join([user.title, user.first_name, user.last_name])

I now emit:

SELECT title FROM user
SELECT first_name FROM user
SELECT last_name FROM user

When what I really want at this point, and can predictably know in this case, 
is:

SELECT title, first_name, last_name FROM user

So, the question is, what is the best way to back-fill an object in a way that 
you keep the number 

Re: [sqlalchemy] Declarative and deferred

2012-08-11 Thread David McKeone
 

 session.refresh(user, [title, first_name, last_name]) 


This was the part that I was missing.  It's fairly readable and it does 
exactly what I'd need.
 


 also, if the columns you're actually using are along these lines, that is, 
 they aren't 10K text files, I'd strongly encourage you to do some actual 
 profiling to determine if all this complexity is necessary and not actually 
 hurting performance much more.To pull over 3K of text over the wire in 
 a single result is probably a lot less overhead than to pull 1000K of text 
 in two or three queries. 


At this point I'm really just exploring the boundaries of the tool so that 
I can select a flexible design.  I still haven't quite found the sweet spot 
between what can/should be lazy and what cannot/shouldn't be lazy.  In the 
existing application (the non-ORM one) all of this is done with an 
abstracted form of direct SQL (kind of like SQLAlchemy core).  I'd like to 
convert some of those sections to use declarative objects instead, so the 
point of of this is to know that if I do go down that path then I could 
still optimize the columns if I needed to (read: after I profiled it and 
determined that it was necessary) without having to drop all the way down 
to SQLAlchemy core and then change things from passing objects around to 
passing keys in some circumstances.  Although it's very likely that you are 
correct and that the complexity induced from using this kind of system may 
outweigh the over-the-wire savings -- I guess we'll see when I get there.


well this is what the group feature does, if any columns in the group are 
 touched, the whole group is loaded.  My advice would be to do some 
 profiling, come up with groups that are tailored close enough to the groups 
 of attributes that tend to be called together, and to not overthink it. 


I will certainly look into this some more, since there are certainly groups 
of columns that can be naturally grouped.  Plus I imagine that 
session.refresh() would load the entire group if an attribute from a group 
was passed to it.  So that could be an interesting way to chunk it.


Thanks for responding with such a great post.  Its certainly helped me 
think through the issues from different angle.

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/sqlalchemy/-/zQNUzzPhzFAJ.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.