coleifer / peewee

a small, expressive orm -- supports postgresql, mysql, sqlite and cockroachdb
http://docs.peewee-orm.com/
MIT License
11.15k stars 1.37k forks source link

max recursion depth exceeded on admin add #80

Closed davidthewatson closed 12 years ago

davidthewatson commented 12 years ago

I've got the following on fedora core 16 with postgresql:

Flask==0.8
Flask-DebugToolbar==0.6.3.1
Flask-OpenID==1.0.1 
Flask-WTF==0.6
Jinja2==2.6 
WTForms==1.0.1
Werkzeug==0.8.3
blinker==1.2
certifi==0.0.8
chardet==1.0.1
diesel==2.1.1
flask-peewee==0.5.1
greenlet==0.3.4
oauthlib==0.1.2
peewee==0.9.5
psycopg2==2.4.5
pyOpenSSL==0.13
pycrypto==2.5
pyev==0.8.1-4.04
python-openid==2.2.5
requests==0.12.0 
wsgiref==0.1.2
wtf-peewee==0.1.3

I have a peewee model like this:

class Pool(db.Model):
    name = CharField()
    active = BooleanField(default=True)
    created = DateTimeField(default=db_now())

    def __unicode__(self):
        return unicode(self.name)

    class Meta:
        db_table = 'mls'

When I access the generated admin at http://localhost:5000/admin/pool/add/

and type a name in the name field with the other two fields defaulting, I get the following:

Traceback (most recent call last): File "/home/watson/git/latte/virtenv/lib/python2.7/site-packages/flask/app.py", line 1506, in wsgi_app response = self.make_response(self.handle_exception(e)) File "/home/watson/git/latte/virtenv/lib/python2.7/site-packages/flask/app.py", line 1504, in wsgi_app response = self.full_dispatch_request() File "/home/watson/git/latte/virtenv/lib/python2.7/site-packages/flask/app.py", line 1264, in full_dispatch_request rv = self.handle_user_exception(e) File "/home/watson/git/latte/virtenv/lib/python2.7/site-packages/flask/app.py", line 1262, in full_dispatch_request rv = self.dispatch_request() File "/home/watson/git/latte/virtenv/lib/python2.7/site-packages/flask_debugtoolbar/init.py", line 101, in dispatch_request return view_func(_req.view_args) File "/usr/lib64/python2.7/cProfile.py", line 149, in runcall return func(_args, _kw) File "/home/watson/git/latte/virtenv/lib/python2.7/site-packages/flask_peewee/admin.py", line 521, in inner return func(_args, kwargs) File "/home/watson/git/latte/virtenv/lib/python2.7/site-packages/flask_peewee/admin.py", line 259, in add instance = self.save_model(self.model(), form, True) File "/home/watson/git/latte/virtenv/lib/python2.7/site-packages/flask_peewee/admin.py", line 200, in save_model instance.save() File "/home/watson/git/latte/virtenv/lib/python2.7/site-packages/peewee.py", line 2586, in save field_dict = self.get_field_dict() File "/home/watson/git/latte/virtenv/lib/python2.7/site-packages/peewee.py", line 2508, in get_field_dict field_dict[field.name] = getattr(self, field.name) File "/home/watson/git/latte/virtenv/lib/python2.7/site-packages/peewee.py", line 2249, in get** query = {self.field_name: instance.get_pk()} File "/home/watson/git/latte/virtenv/lib/python2.7/site-packages/peewee.py", line 2579, in get_pk return getattr(self, self._meta.pk_name, None) File "/home/watson/git/latte/virtenv/lib/python2.7/site-packages/peewee.py", line 2249, in get query = {self.field_name: instance.get_pk()} File "/home/watson/git/latte/virtenv/lib/python2.7/site-packages/peewee.py", line 2579, in get_pk return getattr(self, self._meta.pk_name, None) File "/home/watson/git/latte/virtenv/lib/python2.7/site-packages/peewee.py", line 2249, in get query = {self.field_name: instance.get_pk()} File "/home/watson/git/latte/virtenv/lib/python2.7/site-packages/peewee.py", line 2579, in get_pk return getattr(self, self._meta.pk_name, None) File "/home/watson/git/latte/virtenv/lib/python2.7/site-packages/peewee.py", line 2249, in get query = {self.field_name: instance.get_pk()} File "/home/watson/git/latte/virtenv/lib/python2.7/site-packages/peewee.py", line 2579, in get_pk return getattr(self, self._meta.pk_name, None) File "/home/watson/git/latte/virtenv/lib/python2.7/site-packages/peewee.py", line 2249, in get query = {self.field_name: instance.get_pk()} File "/home/watson/git/latte/virtenv/lib/python2.7/site-packages/peewee.py", line 2579, in get_pk return getattr(self, self._meta.pk_name, None)

coleifer commented 12 years ago

What is the db_now() function? btw, i truncated your stacktrace, there were hundreds of lines of dupe data.

coleifer commented 12 years ago

I should add that I do not experience this problem locally and the test suite is passing. Have you tried running the example app that ships w/flask-peewee and do you observe the same thing?

coleifer commented 12 years ago

Hmm, another consideration -- do you have another model which foreign keys to Pool and specifies a related_name? The reason I ask is that the __get__() is a method on the ReverseForeignRelatedObject...the only reason I can think that it would be called when doing the get_field_dict() is if its name collided with an existing field name. Can you do some interactive debugging and find out what field is causing the recursion? That might help.

davidthewatson commented 12 years ago

Yep, that's it. I had two models that specified related_name='id' which is obviously stupid. I just didn't see how that was going to manifest at runtime and that its effect was catastrophic. Thanks for your help.

coleifer commented 12 years ago

Glad it fixed it -- yes, related_name is used for the back-side of a foreign key, so 0..n related models. Typically they are expressed as a plural, i.e. for message in user.messages: Where Message has a Foreign key to user that looks like user = ForeignKeyField(User, related_name='messages')