librelist archives

« back to archive

Simple (?) Flask-SQLAlchemy problem

Simple (?) Flask-SQLAlchemy problem

From:
Bruce Eckel
Date:
2013-01-03 @ 06:43
I've been using Flask in earnest for about a week, and just switched over
to SQLAlchemy today. I'm trying to solve what I think should be a simple
problem, and have just been thrashing about in it.

I'm really just looking for the simplest, most straightforward (and easy
for a newbie to understand) approach to a solution.

A Person has a name, a Workgroup that he/she is in along with other
Persons, and a list of PreviousPairings of Persons that they've already
been partnered with. Here's the data model the way I have it set up now,
which sort of works (well, I can load data into Persons but not much else)
but for one thing I can't quite figure out how the constructors and "add"
methods should go. Or if I've even approached things in a reasonable way.
Would love to see a clean solution from someone with more than a day's
experience. Thanks!

(note there are some artifacts left from previous thrashings-about).

def sanitize(first, last):
    def san(nm):
        return " ".join([part.strip().capitalize().replace(",", "") for
part in nm.split()])
    return san(first) + " " + san(last)


class Person(db.Model):
    __tablename__ = 'person'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80), unique=True)
    workGroup = db.relationship("WorkGroup", uselist=False,
backref="person")
    prevPairings = db.relationship("PreviousPairings")

    def __init__(self, first, last):
        self.name = sanitize(first, last)

    def __repr__(self):
        return self.name

    def findPartner(self, amongPeople):
        if self.workGroup:
            return # You already have a group
        candidates = [p for p in amongPeople if p is not self and p not in
self.prevPairings and not p.workGroup]
        assert candidates
        newPartner = candidates[0] # Just choose the first available
        WorkGroup(self, newPartner)

    def show(self):
        print "<Person %r %r %r %r>" % (self.id, self.name,
self.prevPairings, self.workGroup)


class PreviousPairings(db.Model):
    __tablename__ = 'previouspairings'
    id = db.Column(db.Integer, primary_key=True)
    person_id = db.Column(db.Integer, db.ForeignKey('person.id'))
    people = db.relationship('Person')


class WorkGroup(db.Model):
    __tablename__ = 'workgroup'
    id = db.Column(db.Integer, primary_key=True)
    person_id = db.Column(db.Integer, db.ForeignKey('person.id'))
    people = db.relationship('Person')
    #workGroup = db.relationship('Person', backref='workGroup')

    def __init__(self, *partners):
        self.people = []
        for partner in partners:
            self.people.append(partner)

    def include(self, newMember):
        assert isinstance(newMember, Person)
        self.add(newMember)

    def members(self):
        return set(self.workGroup)

    def __nonzero__(self):
        return bool(self.workGroup)

    def __iter__(self):
        return iter(self.workGroup)

    def clear(self):
        self.workGroup = []

    def __str__(self): return str(self.workGroup)
    def __repr__(self): return self.__str__()




-- Bruce Eckel
www.AtomicScala.com
www.Reinventing-Business.com
www.MindviewInc.com

Re: [flask] Simple (?) Flask-SQLAlchemy problem

From:
Shriram Kunchanapalli
Date:
2013-01-03 @ 14:42
Assumptions:

-A person can be more than one Workgroup
-Workgroup can have more than one person
So, a Many -Many relation

app = Flask(__name__)
db = SQLALchemy(app)
from flask import session
if __name__ == "__main__":
    db.create_all()

These sections can be addressed again

>         newPartner = candidates[0] # Just choose the first available
>         WorkGroup(self, newPartner)
>
Self can be ignored as a parameter
#newpair = reviousPairings(newPartner)
#db.session.add(newpair)



> class PreviousPairings(db.Model):
>     __tablename__ = 'previouspairings'
>     id = db.Column(db.Integer, primary_key=True)
>     person_id = db.Column(db.Integer, db.ForeignKey('person.id'))
>     people = db.relationship('Person')
>

 def __init__(self, partner):
       assert isinstance(partner, Person)
        self.add(newMember)




>  class WorkGroup(db.Model):
>     __tablename__ = 'workgroup'
>     id = db.Column(db.Integer, primary_key=True)
>     person_id = db.Column(db.Integer, db.ForeignKey('person.id'))
>     people = db.relationship('Person')
>     #workGroup = db.relationship('Person', backref='workGroup')
>
>     def __init__(self, *partners):
>         self.people = []
>         for partner in partners:
>             self.people.append(partner)
>
>     def include(self, newMember):
>         assert isinstance(newMember, Person)
>         self.add(newMember)
>

Re: [flask] Simple (?) Flask-SQLAlchemy problem

From:
Shriram Kunchanapalli
Date:
2013-01-03 @ 14:44
Sorry, I've just noticed the recent update.
I will go through it

Re: [flask] Simple (?) Flask-SQLAlchemy problem

From:
Bruce Eckel
Date:
2013-01-03 @ 15:05
Actually, a Person can only be in one workgroup. A Workgroup has more than
one person in it.

-- Bruce Eckel
www.AtomicScala.com
www.Reinventing-Business.com
www.MindviewInc.com


On Thu, Jan 3, 2013 at 7:44 AM, Shriram Kunchanapalli
<kshriram18@gmail.com>wrote:

> Sorry, I've just noticed the recent update.
> I will go through it
>

Re: [flask] Simple (?) Flask-SQLAlchemy problem

From:
Bruce Eckel
Date:
2013-01-03 @ 15:05
Also, is this the right place to ask such a question or would I be better
off on StackOverflow? Thanks...

-- Bruce Eckel
www.AtomicScala.com
www.Reinventing-Business.com
www.MindviewInc.com


On Thu, Jan 3, 2013 at 8:05 AM, Bruce Eckel <bruceteckel@gmail.com> wrote:

> Actually, a Person can only be in one workgroup. A Workgroup has more than
> one person in it.
>
>
> -- Bruce Eckel
> www.AtomicScala.com
> www.Reinventing-Business.com
> www.MindviewInc.com
>
>
> On Thu, Jan 3, 2013 at 7:44 AM, Shriram Kunchanapalli <
> kshriram18@gmail.com> wrote:
>
>> Sorry, I've just noticed the recent update.
>> I will go through it
>>
>
>

Re: [flask] Simple (?) Flask-SQLAlchemy problem

From:
Shriram Kunchanapalli
Date:
2013-01-03 @ 16:03
Yes, this is the right place.
Both are fine.
There might be a similar question in the archives of mailing list.
It could also help you with this problem.

On Thu, Jan 3, 2013 at 8:35 PM, Bruce Eckel <bruceteckel@gmail.com> wrote:

> Also, is this the right place to ask such a question or would I be better
> off on StackOverflow? Thanks...
>
>
> -- Bruce Eckel
> www.AtomicScala.com
> www.Reinventing-Business.com
> www.MindviewInc.com
>
>
> On Thu, Jan 3, 2013 at 8:05 AM, Bruce Eckel <bruceteckel@gmail.com> wrote:
>
>> Actually, a Person can only be in one workgroup. A Workgroup has more
>> than one person in it.
>>
>>
>> -- Bruce Eckel
>> www.AtomicScala.com
>> www.Reinventing-Business.com
>> www.MindviewInc.com
>>
>>
>> On Thu, Jan 3, 2013 at 7:44 AM, Shriram Kunchanapalli <
>> kshriram18@gmail.com> wrote:
>>
>>> Sorry, I've just noticed the recent update.
>>> I will go through it
>>>
>>
>>
>

Re: [flask] Simple (?) Flask-SQLAlchemy problem

From:
Bruce Eckel
Date:
2013-01-03 @ 17:24
I've posted a slightly updated version as a question to Stackoverflow:

http://stackoverflow.com/questions/14143429/flask-sqlalchemy-data-model-relationship-problems

-- Bruce Eckel
www.AtomicScala.com
www.Reinventing-Business.com
www.MindviewInc.com


On Thu, Jan 3, 2013 at 9:03 AM, Shriram Kunchanapalli
<kshriram18@gmail.com>wrote:

> Yes, this is the right place.
> Both are fine.
> There might be a similar question in the archives of mailing list.
> It could also help you with this problem.
>
>
> On Thu, Jan 3, 2013 at 8:35 PM, Bruce Eckel <bruceteckel@gmail.com> wrote:
>
>> Also, is this the right place to ask such a question or would I be better
>> off on StackOverflow? Thanks...
>>
>>
>> -- Bruce Eckel
>> www.AtomicScala.com
>> www.Reinventing-Business.com
>> www.MindviewInc.com
>>
>>
>> On Thu, Jan 3, 2013 at 8:05 AM, Bruce Eckel <bruceteckel@gmail.com>wrote:
>>
>>> Actually, a Person can only be in one workgroup. A Workgroup has more
>>> than one person in it.
>>>
>>>
>>> -- Bruce Eckel
>>> www.AtomicScala.com
>>> www.Reinventing-Business.com
>>> www.MindviewInc.com
>>>
>>>
>>> On Thu, Jan 3, 2013 at 7:44 AM, Shriram Kunchanapalli <
>>> kshriram18@gmail.com> wrote:
>>>
>>>> Sorry, I've just noticed the recent update.
>>>> I will go through it
>>>>
>>>
>>>
>>
>

Re: [flask] Simple (?) Flask-SQLAlchemy problem

From:
Audrius Kažukauskas
Date:
2013-01-04 @ 10:45
Hi, Bruce,

On Thu, 2013-01-03 at 10:24:00 -0700, Bruce Eckel wrote:
> I've posted a slightly updated version as a question to Stackoverflow:
> 
http://stackoverflow.com/questions/14143429/flask-sqlalchemy-data-model-relationship-problems

Sorry for coming back to you late, it was already too late in my
timezone (Eastern Europe, UTC+2).  I decided to move the discussion from
StackOverflow back to this mailing list, since SO doesn't feel like a
good place for lengthy discussions.

In one of your previous emails you wrote that "a Person can only be in
one workgroup.  A WorkGroup has more than one person in it".  From this
I see that relationship between Person and WorkGroup is set incorrectly.
The foreign key has to be defined inside Person (a person can only
belong to one workgroup), not the other way.  So here's how it should
look:

  class Person(db.Model):
      # ...
      workgroup_id = db.Column(db.Integer, db.ForeignKey('workgroup.id'))
      workGroup = db.relationship("WorkGroup", backref='members')
      # ...

  class WorkGroup(db.Model):
      # ...
      # Removed members_id and members.
      # ...

See http://docs.sqlalchemy.org/en/rel_0_8/orm/relationships.html#many-to-one
for more explanations.

Unfortunately, this leads to another problem: SQLAlchemy raises
CircularDependencyError exception.  So now I'm stuck here.  If I figure
this out, I'll post back to you, unless you or someone else will find a
solution earlier.

-- 
Audrius Kažukauskas
http://neutrino.lt/

Re: [flask] Simple (?) Flask-SQLAlchemy problem

From:
Audrius Kažukauskas
Date:
2013-01-04 @ 13:53
On Fri, 2013-01-04 at 12:45:36 +0200, Audrius Kažukauskas wrote:
> Unfortunately, this leads to another problem: SQLAlchemy raises
> CircularDependencyError exception.  So now I'm stuck here.  If I figure
> this out, I'll post back to you, unless you or someone else will find a
> solution earlier.

I managed to fix CircularDependencyError by reading SA docs about it
(what a surprise!).  The only thing that's needed was to set
post_update=True for prevPairings relationship, since it can point to
itself if my understanding is correct.  See
http://docs.sqlalchemy.org/en/rel_0_8/orm/relationships.html#post-update
to learn more about it.

So the final changes for Person class are (WorkGroup class stays the
same as in my previous email):

  class Person(db.Model):
      # ...
      workgroup_id = db.Column(db.Integer, db.ForeignKey('workgroup.id'))
      workGroup = db.relationship("WorkGroup", backref='members')
      # ...
      prevPairings = db.relationship('Person', post_update=True)
      # ...

I'll update my StackOverflow answer as well.

-- 
Audrius Kažukauskas
http://neutrino.lt/

Re: [flask] Simple (?) Flask-SQLAlchemy problem

From:
Bruce Eckel
Date:
2013-01-04 @ 14:22
OK, that does work but ... wow. It doesn't seem that obvious to me that
this should have been the answer. I find it a little intimidating that what
seems like such a simple relationship should be so tricky to get right.

Anyway, thanks very much for the help. Now I can see if I can solve the
algorithmic problem that makes the system run out of match candidates so
quickly.

If anyone else is interested, post a message here and I'll put up the
current version of the project.

-- Bruce Eckel
www.AtomicScala.com
www.Reinventing-Business.com
www.MindviewInc.com


On Fri, Jan 4, 2013 at 6:53 AM, Audrius Kažukauskas <audrius@neutrino.lt>wrote:

> On Fri, 2013-01-04 at 12:45:36 +0200, Audrius Kažukauskas wrote:
> > Unfortunately, this leads to another problem: SQLAlchemy raises
> > CircularDependencyError exception.  So now I'm stuck here.  If I figure
> > this out, I'll post back to you, unless you or someone else will find a
> > solution earlier.
>
> I managed to fix CircularDependencyError by reading SA docs about it
> (what a surprise!).  The only thing that's needed was to set
> post_update=True for prevPairings relationship, since it can point to
> itself if my understanding is correct.  See
> http://docs.sqlalchemy.org/en/rel_0_8/orm/relationships.html#post-update
> to learn more about it.
>
> So the final changes for Person class are (WorkGroup class stays the
> same as in my previous email):
>
>   class Person(db.Model):
>       # ...
>       workgroup_id = db.Column(db.Integer, db.ForeignKey('workgroup.id'))
>       workGroup = db.relationship("WorkGroup", backref='members')
>       # ...
>       prevPairings = db.relationship('Person', post_update=True)
>       # ...
>
> I'll update my StackOverflow answer as well.
>
> --
> Audrius Kažukauskas
> http://neutrino.lt/
>

Re: [flask] Simple (?) Flask-SQLAlchemy problem

From:
Matt Good
Date:
2013-01-04 @ 18:13
Models referencing themselves seems simple enough, but it does seem to get
tricky to model with SQLAlchemy.

While the "post_update" change gets rid of the error, but it gives an 
incorrect answer, since the code now only has a Person related to one 
other Person.  This would work for parent/child hierarchies where a child 
has exactly one parent, but to store a many-to-many relationship between 
partners you'll need the extra table to store the pairs.

You'll need something along these lines to model a self-referential 
many-to-many relationship between a person and their past partners:

  
http://docs.sqlalchemy.org/en/latest/orm/relationships.html#self-referential-many-to-many

In the above example, nodes have a left/right pairing, which means that 
the relationship is directional (left->right).  So, you'll need to take 
that into account, and either check both sides (left partners and right 
partners), or add rows for both sides of the relationship, e.g.:

  self.prevPairings.append(other)
  other.prevPairings.append(self)

You might also check on the SQLAlchemy mailing list, since you'll find 
people on that list with more specific expertise.

BTW, I love the Buckaroo Banzai sample data :)



On Friday, January 4, 2013 at 6:22 AM, Bruce Eckel wrote:

> OK, that does work but ... wow. It doesn't seem that obvious to me that 
this should have been the answer. I find it a little intimidating that 
what seems like such a simple relationship should be so tricky to get 
right.
>  
> Anyway, thanks very much for the help. Now I can see if I can solve the 
algorithmic problem that makes the system run out of match candidates so 
quickly.
>  
> If anyone else is interested, post a message here and I'll put up the 
current version of the project.
>  
> -- Bruce Eckel
> www.AtomicScala.com (http://www.AtomicScala.com)
> www.Reinventing-Business.com (http://www.Reinventing-Business.com)
> www.MindviewInc.com (http://www.MindviewInc.com)
>  
>  
> On Fri, Jan 4, 2013 at 6:53 AM, Audrius Kažukauskas <audrius@neutrino.lt
(mailto:audrius@neutrino.lt)> wrote:
> > On Fri, 2013-01-04 at 12:45:36 +0200, Audrius Kažukauskas wrote:
> > > Unfortunately, this leads to another problem: SQLAlchemy raises
> > > CircularDependencyError exception. So now I'm stuck here. If I figure
> > > this out, I'll post back to you, unless you or someone else will find a
> > > solution earlier.
> >  
> >  
> > I managed to fix CircularDependencyError by reading SA docs about it
> > (what a surprise!). The only thing that's needed was to set
> > post_update=True for prevPairings relationship, since it can point to
> > itself if my understanding is correct. See
> > http://docs.sqlalchemy.org/en/rel_0_8/orm/relationships.html#post-update
> > to learn more about it.
> >  
> > So the final changes for Person class are (WorkGroup class stays the
> > same as in my previous email):
> >  
> > class Person(db.Model):
> > # ...
> > workgroup_id = db.Column(db.Integer, db.ForeignKey('workgroup.id 
(http://workgroup.id)'))
> > workGroup = db.relationship("WorkGroup", backref='members')
> > # ...
> > prevPairings = db.relationship('Person', post_update=True)
> > # ...
> >  
> > I'll update my StackOverflow answer as well.
> >  
> > --
> > Audrius Kažukauskas
> > http://neutrino.lt/
>  


Re: [flask] Simple (?) Flask-SQLAlchemy problem

From:
Bruce Eckel
Date:
2013-01-04 @ 13:54
What if I enforce that relationship programmatically rather than trying to
get SQLAlchemy to do it? Although it seems to me that SQLAlchemy *must* be
able to handle a relationship this simple, right now I'm just trying to get
the system to work at all for the conference next week, so anything that
just works is acceptable.

For anyone reading this who'd like to try it, the whole project as a zip
file is downloadable here:
https://www.dropbox.com/s/wlbcsj9bst4te74/AtomicScalaSeminarLocalServer.zip

(This mailing list apparently doesn't allow attachments). All you have to
do is unzip it, "pip install" any libraries you're missing, then follow the
instructions in AtomicScalaSeminarSQLAlchemy.py to reproduce the error.

-- Bruce Eckel
www.AtomicScala.com
www.Reinventing-Business.com
www.MindviewInc.com


On Fri, Jan 4, 2013 at 3:45 AM, Audrius Kažukauskas <audrius@neutrino.lt>wrote:

> Hi, Bruce,
>
> On Thu, 2013-01-03 at 10:24:00 -0700, Bruce Eckel wrote:
> > I've posted a slightly updated version as a question to Stackoverflow:
> >
> 
http://stackoverflow.com/questions/14143429/flask-sqlalchemy-data-model-relationship-problems
>
> Sorry for coming back to you late, it was already too late in my
> timezone (Eastern Europe, UTC+2).  I decided to move the discussion from
> StackOverflow back to this mailing list, since SO doesn't feel like a
> good place for lengthy discussions.
>
> In one of your previous emails you wrote that "a Person can only be in
> one workgroup.  A WorkGroup has more than one person in it".  From this
> I see that relationship between Person and WorkGroup is set incorrectly.
> The foreign key has to be defined inside Person (a person can only
> belong to one workgroup), not the other way.  So here's how it should
> look:
>
>   class Person(db.Model):
>       # ...
>       workgroup_id = db.Column(db.Integer, db.ForeignKey('workgroup.id'))
>       workGroup = db.relationship("WorkGroup", backref='members')
>       # ...
>
>   class WorkGroup(db.Model):
>       # ...
>       # Removed members_id and members.
>       # ...
>
> See
> http://docs.sqlalchemy.org/en/rel_0_8/orm/relationships.html#many-to-one
> for more explanations.
>
> Unfortunately, this leads to another problem: SQLAlchemy raises
> CircularDependencyError exception.  So now I'm stuck here.  If I figure
> this out, I'll post back to you, unless you or someone else will find a
> solution earlier.
>
> --
> Audrius Kažukauskas
> http://neutrino.lt/
>

Re: [flask] Simple (?) Flask-SQLAlchemy problem

From:
Teo Klestrup Röijezon
Date:
2013-01-03 @ 09:43
That seems mostly right, but in general your Person.show method is what
you'd put in the __repr__.
Also, a WorkGroup has both "people" and "person"? What?


On 3 January 2013 07:43, Bruce Eckel <bruceteckel@gmail.com> wrote:

> I've been using Flask in earnest for about a week, and just switched over
> to SQLAlchemy today. I'm trying to solve what I think should be a simple
> problem, and have just been thrashing about in it.
>
> I'm really just looking for the simplest, most straightforward (and easy
> for a newbie to understand) approach to a solution.
>
> A Person has a name, a Workgroup that he/she is in along with other
> Persons, and a list of PreviousPairings of Persons that they've already
> been partnered with. Here's the data model the way I have it set up now,
> which sort of works (well, I can load data into Persons but not much else)
> but for one thing I can't quite figure out how the constructors and "add"
> methods should go. Or if I've even approached things in a reasonable way.
> Would love to see a clean solution from someone with more than a day's
> experience. Thanks!
>
> (note there are some artifacts left from previous thrashings-about).
>
> def sanitize(first, last):
>     def san(nm):
>         return " ".join([part.strip().capitalize().replace(",", "") for
> part in nm.split()])
>     return san(first) + " " + san(last)
>
>
> class Person(db.Model):
>     __tablename__ = 'person'
>     id = db.Column(db.Integer, primary_key=True)
>     name = db.Column(db.String(80), unique=True)
>     workGroup = db.relationship("WorkGroup", uselist=False,
> backref="person")
>     prevPairings = db.relationship("PreviousPairings")
>
>     def __init__(self, first, last):
>         self.name = sanitize(first, last)
>
>     def __repr__(self):
>         return self.name
>
>     def findPartner(self, amongPeople):
>         if self.workGroup:
>             return # You already have a group
>         candidates = [p for p in amongPeople if p is not self and p not in
> self.prevPairings and not p.workGroup]
>         assert candidates
>         newPartner = candidates[0] # Just choose the first available
>         WorkGroup(self, newPartner)
>
>     def show(self):
>         print "<Person %r %r %r %r>" % (self.id, self.name,
> self.prevPairings, self.workGroup)
>
>
> class PreviousPairings(db.Model):
>     __tablename__ = 'previouspairings'
>     id = db.Column(db.Integer, primary_key=True)
>     person_id = db.Column(db.Integer, db.ForeignKey('person.id'))
>     people = db.relationship('Person')
>
>
> class WorkGroup(db.Model):
>     __tablename__ = 'workgroup'
>     id = db.Column(db.Integer, primary_key=True)
>     person_id = db.Column(db.Integer, db.ForeignKey('person.id'))
>     people = db.relationship('Person')
>     #workGroup = db.relationship('Person', backref='workGroup')
>
>     def __init__(self, *partners):
>         self.people = []
>         for partner in partners:
>             self.people.append(partner)
>
>     def include(self, newMember):
>         assert isinstance(newMember, Person)
>         self.add(newMember)
>
>     def members(self):
>         return set(self.workGroup)
>
>     def __nonzero__(self):
>         return bool(self.workGroup)
>
>     def __iter__(self):
>         return iter(self.workGroup)
>
>     def clear(self):
>         self.workGroup = []
>
>     def __str__(self): return str(self.workGroup)
>     def __repr__(self): return self.__str__()
>
>
>
>
> -- Bruce Eckel
> www.AtomicScala.com
> www.Reinventing-Business.com
> www.MindviewInc.com
>

Re: [flask] Simple (?) Flask-SQLAlchemy problem

From:
Bruce Eckel
Date:
2013-01-03 @ 14:15
OK, here's where I am now. I realized that prevPairings is just a list of
Person, so I should be able to create a relationship of self-references to
Person *within* Person. Each WorkGroup object is shared among all the
members of the group, so that needs to be a separate object and it also has
a list of Person. Applying that produces the following, which almost works
except for one error message.

class Person(db.Model):
    __tablename__ = 'person'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80), unique=True)
    workGroup = db.relationship("WorkGroup", uselist=False)
    prevPairings_id = db.Column(db.Integer, db.ForeignKey('person.id'))
    prevPairings = db.relationship('Person')

    def __init__(self, first, last):
        self.name = sanitize(first, last)
        self.workGroup = None
        self.prevPairings = []

    def __repr__(self):
        return self.name

    def findPartner(self, amongPeople):
        if self.workGroup:
            return # You already have a group
        candidates = [p for p in amongPeople if p is not self and p not in
self.prevPairings and not p.workGroup]
        assert candidates
        newPartner = candidates[0] # Just choose the first available
        self.prevPairings.append(newPartner)
        newPartner.prevPairings.append(self)
        wg = WorkGroup(self, newPartner)
        #db.session.add(wg)
        newPartner.workGroup = self.workGroup = wg

    def show(self):
        print "<Person %r %r %r %r>" % (self.id, self.name,
self.prevPairings, self.workGroup)


class WorkGroup(db.Model):
    __tablename__ = 'workgroup'
    id = db.Column(db.Integer, primary_key=True)
    members_id = db.Column(db.Integer, db.ForeignKey('person.id'))
    members = db.relationship('Person')

    def __init__(self, *partners):
        self.members = list(partners)

    def include(self, newMember):
        assert isinstance(newMember, Person)
        self.members.append(newMember)


Both the line:
db.session.add(wg)
(When it isn't commented out) Or the line:
newPartner.workGroup = self.workGroup = wg
produce the error message:
AttributeError: 'list' object has no attribute '_sa_instance_state'
Which I find confusing, since it shouldn't be a list (I said uselist=False ).
At at the same time, the manipulations of Person's prevPairings (which is a
list) seems to work OK.

I don't understand how to resolve that error. Thanks for any help you can
give.

-- Bruce Eckel
www.AtomicScala.com
www.Reinventing-Business.com
www.MindviewInc.com


On Thu, Jan 3, 2013 at 2:43 AM, Teo Klestrup Röijezon <teo@nullable.se>wrote:

> That seems mostly right, but in general your Person.show method is what
> you'd put in the __repr__.
> Also, a WorkGroup has both "people" and "person"? What?
>
>
> On 3 January 2013 07:43, Bruce Eckel <bruceteckel@gmail.com> wrote:
>
>> I've been using Flask in earnest for about a week, and just switched over
>> to SQLAlchemy today. I'm trying to solve what I think should be a simple
>> problem, and have just been thrashing about in it.
>>
>> I'm really just looking for the simplest, most straightforward (and easy
>> for a newbie to understand) approach to a solution.
>>
>> A Person has a name, a Workgroup that he/she is in along with other
>> Persons, and a list of PreviousPairings of Persons that they've already
>> been partnered with. Here's the data model the way I have it set up now,
>> which sort of works (well, I can load data into Persons but not much else)
>> but for one thing I can't quite figure out how the constructors and "add"
>> methods should go. Or if I've even approached things in a reasonable way.
>> Would love to see a clean solution from someone with more than a day's
>> experience. Thanks!
>>
>> (note there are some artifacts left from previous thrashings-about).
>>
>> def sanitize(first, last):
>>     def san(nm):
>>         return " ".join([part.strip().capitalize().replace(",", "") for
>> part in nm.split()])
>>     return san(first) + " " + san(last)
>>
>>
>> class Person(db.Model):
>>     __tablename__ = 'person'
>>     id = db.Column(db.Integer, primary_key=True)
>>     name = db.Column(db.String(80), unique=True)
>>     workGroup = db.relationship("WorkGroup", uselist=False,
>> backref="person")
>>     prevPairings = db.relationship("PreviousPairings")
>>
>>     def __init__(self, first, last):
>>         self.name = sanitize(first, last)
>>
>>     def __repr__(self):
>>         return self.name
>>
>>     def findPartner(self, amongPeople):
>>         if self.workGroup:
>>             return # You already have a group
>>         candidates = [p for p in amongPeople if p is not self and p not
>> in self.prevPairings and not p.workGroup]
>>         assert candidates
>>         newPartner = candidates[0] # Just choose the first available
>>         WorkGroup(self, newPartner)
>>
>>     def show(self):
>>         print "<Person %r %r %r %r>" % (self.id, self.name,
>> self.prevPairings, self.workGroup)
>>
>>
>> class PreviousPairings(db.Model):
>>     __tablename__ = 'previouspairings'
>>     id = db.Column(db.Integer, primary_key=True)
>>     person_id = db.Column(db.Integer, db.ForeignKey('person.id'))
>>     people = db.relationship('Person')
>>
>>
>> class WorkGroup(db.Model):
>>     __tablename__ = 'workgroup'
>>     id = db.Column(db.Integer, primary_key=True)
>>     person_id = db.Column(db.Integer, db.ForeignKey('person.id'))
>>     people = db.relationship('Person')
>>     #workGroup = db.relationship('Person', backref='workGroup')
>>
>>     def __init__(self, *partners):
>>         self.people = []
>>         for partner in partners:
>>             self.people.append(partner)
>>
>>     def include(self, newMember):
>>         assert isinstance(newMember, Person)
>>         self.add(newMember)
>>
>>     def members(self):
>>         return set(self.workGroup)
>>
>>     def __nonzero__(self):
>>         return bool(self.workGroup)
>>
>>     def __iter__(self):
>>         return iter(self.workGroup)
>>
>>     def clear(self):
>>         self.workGroup = []
>>
>>     def __str__(self): return str(self.workGroup)
>>     def __repr__(self): return self.__str__()
>>
>>
>>
>>
>> -- Bruce Eckel
>> www.AtomicScala.com
>> www.Reinventing-Business.com
>> www.MindviewInc.com
>>
>
>