0
votes

Edit: Here's the fix for anyone interested. I changed the unicode method in the Events models to the following

class Event(models.Model):
....
def __unicode__(self):
    return '%s %s (%s)' % ((", ".join([str(item)for item in self.branches.all()])) , self.title, self.updated.strftime('%Y-%m-%d'))

(django V1.3, python 2.7)

Title is confusing, I'll do my best to make this clear. I have three models, Branch, Event and Update:

class Branch(models.Model):
    branch = models.CharField(max_length=20)

    def __unicode__(self):
        return self.branch


class Event(models.Model):
    title = models.CharField(max_length=50)
    branches = models.ManyToManyField(Branch)
    updated = models.DateTimeField(auto_now=True)

    def get_branches(self):
        return ", ".join([str(p) for p in self.branches.all()])

    def __unicode__(self):
        return '%s (%s)' % (self.get_branches, self.title, self.updated.strftime('%Y-%m-%d'))


class Update(models.Model):
    title = models.CharField(blank=False, max_length=45)
    body = models.TextField(blank=False)
    related_event = models.ManyToManyField(Event, blank=True)

    def __unicode__(self):
        return self.title

When adding an Update via the admin interface I want the related_event field to display the title, branches and updated fields of the Event model to make selecting the correct related_event easier for a user (rather than just a long list of titles).

Example of how I want this to display in a pulldown or horizontal related_event admin field when adding an Update: ThisIsATitle Branch1, Branch2 (yyyy-mm-dd)

I have this simple function in the Event model that gets all branches for an Event and joins them into a string which I successfully use in the list_display of the Event admin page:

def get_branches(self):
    return ", ".join([str(p) for p in self.branches.all()])

Event Admin:

...
list_display = ('title','get_branches', 'updated')
...

I thought I could use that function like so to achieve what I want:

def __unicode__(self):
    return '%s (%s)' % (self.get_branches, self.title, self.updated.strftime('%Y-%m-%d'))

But it throws a maximum recursion depth error (works fine for just title and updated.


TemplateSyntaxError at /admin/myapp/update/8/

Caught RuntimeError while rendering: maximum recursion depth exceeded while calling a Python object

Request Method: GET

Request URL: http://example.com/admin/myapp/update/8/

Django Version: 1.3 beta 1 SVN-15248

Exception Type: TemplateSyntaxError

Exception Value:

Caught RuntimeError while rendering: maximum recursion depth exceeded while calling a Python object

Exception Location: /usr/share/django-apps/scpl/measures/models.py in unicode, line 168

Python Executable: /usr/bin/python

Environment:

Template error:

In template /usr/local/lib/python2.7/dist-packages/django/contrib/admin/templates/admin/includes/fieldset.html, error at line 19

Caught RuntimeError while rendering: maximum recursion depth exceeded while calling a Python object

Traceback:

File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py" in get_response

  1. response = callback(request, *callback_args, **callback_kwargs)

File "/usr/local/lib/python2.7/dist-packages/django/contrib/admin/options.py" in wrapper

  1. return self.admin_site.admin_view(view)(*args, **kwargs)

File "/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py" in _wrapped_view

  1. response = view_func(request, *args, **kwargs)

File "/usr/local/lib/python2.7/dist-packages/django/views/decorators/cache.py" in _wrapped_view_func

  1. response = view_func(request, *args, **kwargs)

File "/usr/local/lib/python2.7/dist-packages/django/contrib/admin/sites.py" in inner

  1. return view(request, *args, **kwargs)

File "/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py" in _wrapper

  1. return bound_func(*args, **kwargs)

File "/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py" in _wrapped_view

  1. response = view_func(request, *args, **kwargs)

File "/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py" in bound_func

  1. return func(self, *args2, **kwargs2)

File "/usr/local/lib/python2.7/dist-packages/django/db/transaction.py" in inner

  1. res = func(*args, **kwargs)

File "/usr/local/lib/python2.7/dist-packages/django/contrib/admin/options.py" in change_view

  1. return self.render_change_form(request, context, change=True, obj=obj)

File "/usr/local/lib/python2.7/dist-packages/django/contrib/admin/options.py" in render_change_form

  1. ], context, context_instance=context_instance)

File "/usr/local/lib/python2.7/dist-packages/django/shortcuts/init.py" in render_to_response

  1. return HttpResponse(loader.render_to_string(*args, **kwargs), **httpresponse_kwargs)

File "/usr/local/lib/python2.7/dist-packages/django/template/loader.py" in render_to_string

  1. return t.render(context_instance)

...

  1. bits.append(self.render_node(node, context))

File "/usr/local/lib/python2.7/dist-packages/django/template/debug.py" in render_node

  1. result = node.render(context)

File "/usr/local/lib/python2.7/dist-packages/django/template/defaulttags.py" in render

  1. return self.nodelist_false.render(context)

File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render

  1. bits.append(self.render_node(node, context))

File "/usr/local/lib/python2.7/dist-packages/django/template/debug.py" in render_node

  1. result = node.render(context)

File "/usr/local/lib/python2.7/dist-packages/django/template/debug.py" in render

  1. output = force_unicode(output)

File "/usr/local/lib/python2.7/dist-packages/django/utils/encoding.py" in force_unicode

  1. s = unicode(s)

File "/usr/local/lib/python2.7/dist-packages/django/forms/forms.py" in unicode

  1. return self.as_widget()

File "/usr/local/lib/python2.7/dist-packages/django/forms/forms.py" in as_widget

  1. return widget.render(name, self.value(), attrs=attrs)

File "/usr/local/lib/python2.7/dist-packages/django/contrib/admin/widgets.py" in render

  1. output = [self.widget.render(name, value, *args, **kwargs)]

File "/usr/local/lib/python2.7/dist-packages/django/contrib/admin/widgets.py" in render

  1. output = [super(FilteredSelectMultiple, self).render(name, value, attrs, choices)]

File "/usr/local/lib/python2.7/dist-packages/django/forms/widgets.py" in render

  1. options = self.render_options(choices, value)

File "/usr/local/lib/python2.7/dist-packages/django/forms/widgets.py" in render_options

  1. for option_value, option_label in chain(self.choices, choices):

File "/usr/local/lib/python2.7/dist-packages/django/forms/models.py" in iter

  1. yield self.choice(obj)

File "/usr/local/lib/python2.7/dist-packages/django/forms/models.py" in choice

  1. return (self.field.prepare_value(obj), self.field.label_from_instance(obj))

File "/usr/local/lib/python2.7/dist-packages/django/forms/models.py" in label_from_instance

  1. return smart_unicode(obj)

File "/usr/local/lib/python2.7/dist-packages/django/utils/encoding.py" in smart_unicode

  1. return force_unicode(s, encoding, strings_only, errors)

File "/usr/local/lib/python2.7/dist-packages/django/utils/encoding.py" in force_unicode

  1. s = unicode(s)

...

Exception Type: TemplateSyntaxError at /admin/measures/update/8/

Exception Value: Caught RuntimeError while rendering: maximum recursion depth exceeded while calling a Python object

1
Not that this is relevant, but I’d recommend upgrading to version 1.10.1 from the unsupported and insecure 1.3.Jed Fox
Unfortunately upgrading is not an option at this time. We are in the process of building a new web server in anticipation of the next LTS releaseFish
Do you have the appropriate inlines in the Event admin?Jed Fox
I don't need to make changes to any other model from the Update admin interface so I don't need inlines.Fish
Could you put a snippet of the recursion error stack trace?Jed Fox

1 Answers

2
votes

You have a typo in you Event's __unicode__ method.

You're doing self.get_branches, but you're not calling it (like self.get_branches()).

This will try to print something like 'method of object...' which may try to call __unicode__ again, thus causing the loop.