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 release - Fish
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.