﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
5302	unique and editinline bug	patrick.lauber@…	Adrian Holovaty	"the following model can not be saved in admin:

{{{
class CourseCollection(models.Model):
    course_type=models.ForeignKey(CourseType)
    days=models.PositiveSmallIntegerField(_(""Tage""))
    popup_text=models.TextField(_(""Popup Text""))
    info=models.CharField(_(""Zusatz Info""),maxlength=100)
    prize=models.PositiveSmallIntegerField(_(""Preis""))
    class Admin:
        list_display = ('course_type','type','days','prize')
        list_filter = ('course_type','days','prize')
        search_fields = ('popup_text','info')
    class Meta:
        verbose_name=_('Kurs Gruppe')
        verbose_name_plural=_('Kurs Gruppen')
    def __unicode__(self):
        return ""%s(%s)"" %(self.course_type,unicode(self.type))
        
class Course(models.Model):
    course_collection=models.ForeignKey(CourseCollection,edit_inline=models.TABULAR,num_in_admin=40)
    code=models.CharField(_(""Code""),maxlength=8,unique=True)
    location=models.ForeignKey(Location,core=True)
    start_date=models.DateField(_(""Start Datum""),default=datetime.date.today)
    examination_date=models.DateField(_(u""Prüfungs Datum""),null=True,blank=True)
}}}

the problem lies with the code field in the Course model.  As long as there is a unique=True it will raise the following exception:

{{

TypeError at /admin/courses/coursecollection/1/
Cannot resolve keyword 'coda' into field. Choices are: course, id, course_type, type, days, popup_text, info, prize
Request Method: 	POST
Request URL: 	http://localhost:8000/admin/courses/coursecollection/1/
Exception Type: 	TypeError
Exception Value: 	Cannot resolve keyword 'coda' into field. Choices are: course, id, course_type, type, days, popup_text, info, prize
Exception Location: 	/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/django/db/models/query.py in lookup_inner, line 1039
Python Executable: 	/Library/Frameworks/Python.framework/Versions/2.5/Resources/Python.app/Contents/MacOS/Python
Python Version: 	2.5.1
Traceback (innermost last)
Switch to copy-and-paste view

    * /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/django/core/handlers/base.py in get_response
        65.
        66. resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)
        67. try:
        68. callback, callback_args, callback_kwargs = resolver.resolve(request.path)
        69.
        70. # Apply view middleware
        71. for middleware_method in self._view_middleware:
        72. response = middleware_method(request, callback, callback_args, callback_kwargs) ...
        73. if response:
        74. return response
        75.
        76. try:
        77. response = callback(request, *callback_args, **callback_kwargs)
        78. except Exception, e:
      ▶ Local vars
      Variable 	Value
      callback 	
      <function _checklogin at 0x2301c30>
      callback_args 	
      (u'courses', u'coursecollection', u'1')
      callback_kwargs 	
      {}
      debug 	
      <module 'django.views.debug' from '/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/django/views/debug.pyc'>
      exceptions 	
      <module 'django.core.exceptions' from '/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/django/core/exceptions.pyc'>
      mail_admins 	
      <function mail_admins at 0x22a96b0>
      middleware_method 	
      <bound method StatsMiddleware.process_view of <divio.middleware.stats.StatsMiddleware object at 0x22ae230>>
      request 	
      <WSGIRequest GET:<MultiValueDict: {}>, POST:<MultiValueDict: {u'info': [u'Bei ungen\xfcgender Anzahl Anmeldungen werden die Kurse koordiniert.'], u'course.0.location': [u'1'], u'course.0.examination_date': [u''], u'course.1.examination_date': [u''], u'prize': [u'590'], u'course.1.start_date': [u'2007-08-30'], u'days': [u'12'], u'course_type': [u'1'], u'course.1.coda': [u'dsf'], u'course.0.id': [u'1'], u'course.1.id': [u''], u'course.1.location': [u'1'], u'popup_text': [u'12 Kursabende 19.00 - 21.30 h / 19.15 - 21.45 h\r\nzus\xe4tzlich 1 ganzt\xe4giges Meteoseminar Basis'], u'course.0.coda': [u'dfs'], u'type': [u'0'], u'course.0.start_date': [u'2007-08-30']}>, COOKIES:{'sessionid': '02ec2573a0cb5bcda106515624beb12b'}, META:{'ADMINMEDIA': '/Users/patricklauber/Documents/workspace/divio.django/httpdocs/admin_media:', 'CONTENT_LENGTH': '453', 'CONTENT_TYPE': 'application/x-www-form-urlencoded', 'DJANGO_SETTINGS_MODULE': 'hoz.settings', 'GATEWAY_INTERFACE': 'CGI/1.1', 'HOME': '/Users/patricklauber', 'HTTP_ACCEPT': 'text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5', 'HTTP_ACCEPT_CHARSET': 'ISO-8859-1,utf-8;q=0.7,*;q=0.7', 'HTTP_ACCEPT_ENCODING': 'gzip,deflate', 'HTTP_ACCEPT_LANGUAGE': 'de-ch,de;q=0.8,en-us;q=0.5,en;q=0.3', 'HTTP_CONNECTION': 'keep-alive', 'HTTP_COOKIE': 'sessionid=02ec2573a0cb5bcda106515624beb12b', 'HTTP_HOST': 'localhost:8000', 'HTTP_KEEP_ALIVE': '300', 'HTTP_REFERER': 'http://localhost:8000/admin/courses/coursecollection/1/', 'HTTP_USER_AGENT': 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6', 'PATH': '/usr/local/Trolltech/Qt-4.3.0/bin:/Users/patricklauber/Documents/workspace/django/django/bin:/usr/local/mysql-5.0.37-osx10.4-i686/bin:/sw/bin:/usr/local/bin:/Library/Frameworks/Python.framework/Versions/Current/bin:/bin:/sbin:/usr/bin:/usr/sbin', 'PATH_INFO': '/admin/courses/coursecollection/1/', 'PWD': '/Users/patricklauber/Documents/workspace/html.hoz.ch/py_src/hoz', 'PYTHONPATH': '..:/Users/patricklauber/Documents/workspace/divio.django/src/:/Users/patricklauber/Documents/workspace/divio.django/src:', 'QUERY_STRING': '', 'REMOTE_ADDR': '127.0.0.1', 'REMOTE_HOST': '', 'REQUEST_METHOD': 'POST', 'RUN_MAIN': 'true', 'SCRIPT_NAME': '', 'SECURITYSESSIONID': 'b96da0', 'SERVER_NAME': 'localhost\r', 'SERVER_PORT': '8000', 'SERVER_PROTOCOL': 'HTTP/1.1', 'SERVER_SOFTWARE': 'WSGIServer/0.1 Python/2.5.1', 'SHELL': '/bin/bash', 'SHLVL': '1', 'TERM': 'xterm-new', 'TERM_PROGRAM': 'iTerm.app', 'TZ': 'Europe/Zurich', 'USER': 'patricklauber', '_': '/usr/local/bin/python', '__CF_USER_TEXT_ENCODING': '0x1F5:0:0', 'wsgi.errors': <open file '<stderr>', mode 'w' at 0x130b0>, 'wsgi.file_wrapper': <class 'django.core.servers.basehttp.FileWrapper'>, 'wsgi.input': <socket._fileobject object at 0x1095f30>, 'wsgi.multiprocess': False, 'wsgi.multithread': True, 'wsgi.run_once': False, 'wsgi.url_scheme': 'http', 'wsgi.version': (1, 0)}>
      resolver 	
      <RegexURLResolver hoz.urls ^/>
      response 	
      None
      self 	
      <django.core.handlers.wsgi.WSGIHandler object at 0x11aad70>
      settings 	
      <django.conf.LazySettings object at 0xea590>
      urlconf 	
      u'hoz.urls'
      urlresolvers 	
      <module 'django.core.urlresolvers' from '/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/django/core/urlresolvers.pyc'>
    * /Users/patricklauber/Documents/workspace/divio.django/src/divio/middleware/stats.py in process_view
        20. settings.DEBUG = True
        21.
        22. # get number of db queries before we do anything
        23. n = len(connection.queries)
        24.
        25. # time the view
        26. start = time() 
        27. response = view_func(request, *view_args, **view_kwargs) ...
        28. totTime = time() - start
        29.
        30. # compute the db time for the queries just run
        31. queries = len(connection.queries) - n
        32. if queries:
        33. dbTime = reduce(add, [float(q['time']) 
      ▶ Local vars
      Variable 	Value
      debug 	
      True
      n 	
      1
      request 	
      <WSGIRequest GET:<MultiValueDict: {}>, POST:<MultiValueDict: {u'info': [u'Bei ungen\xfcgender Anzahl Anmeldungen werden die Kurse koordiniert.'], u'course.0.location': [u'1'], u'course.0.examination_date': [u''], u'course.1.examination_date': [u''], u'prize': [u'590'], u'course.1.start_date': [u'2007-08-30'], u'days': [u'12'], u'course_type': [u'1'], u'course.1.coda': [u'dsf'], u'course.0.id': [u'1'], u'course.1.id': [u''], u'course.1.location': [u'1'], u'popup_text': [u'12 Kursabende 19.00 - 21.30 h / 19.15 - 21.45 h\r\nzus\xe4tzlich 1 ganzt\xe4giges Meteoseminar Basis'], u'course.0.coda': [u'dfs'], u'type': [u'0'], u'course.0.start_date': [u'2007-08-30']}>, COOKIES:{'sessionid': '02ec2573a0cb5bcda106515624beb12b'}, META:{'ADMINMEDIA': '/Users/patricklauber/Documents/workspace/divio.django/httpdocs/admin_media:', 'CONTENT_LENGTH': '453', 'CONTENT_TYPE': 'application/x-www-form-urlencoded', 'DJANGO_SETTINGS_MODULE': 'hoz.settings', 'GATEWAY_INTERFACE': 'CGI/1.1', 'HOME': '/Users/patricklauber', 'HTTP_ACCEPT': 'text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5', 'HTTP_ACCEPT_CHARSET': 'ISO-8859-1,utf-8;q=0.7,*;q=0.7', 'HTTP_ACCEPT_ENCODING': 'gzip,deflate', 'HTTP_ACCEPT_LANGUAGE': 'de-ch,de;q=0.8,en-us;q=0.5,en;q=0.3', 'HTTP_CONNECTION': 'keep-alive', 'HTTP_COOKIE': 'sessionid=02ec2573a0cb5bcda106515624beb12b', 'HTTP_HOST': 'localhost:8000', 'HTTP_KEEP_ALIVE': '300', 'HTTP_REFERER': 'http://localhost:8000/admin/courses/coursecollection/1/', 'HTTP_USER_AGENT': 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6', 'PATH': '/usr/local/Trolltech/Qt-4.3.0/bin:/Users/patricklauber/Documents/workspace/django/django/bin:/usr/local/mysql-5.0.37-osx10.4-i686/bin:/sw/bin:/usr/local/bin:/Library/Frameworks/Python.framework/Versions/Current/bin:/bin:/sbin:/usr/bin:/usr/sbin', 'PATH_INFO': '/admin/courses/coursecollection/1/', 'PWD': '/Users/patricklauber/Documents/workspace/html.hoz.ch/py_src/hoz', 'PYTHONPATH': '..:/Users/patricklauber/Documents/workspace/divio.django/src/:/Users/patricklauber/Documents/workspace/divio.django/src:', 'QUERY_STRING': '', 'REMOTE_ADDR': '127.0.0.1', 'REMOTE_HOST': '', 'REQUEST_METHOD': 'POST', 'RUN_MAIN': 'true', 'SCRIPT_NAME': '', 'SECURITYSESSIONID': 'b96da0', 'SERVER_NAME': 'localhost\r', 'SERVER_PORT': '8000', 'SERVER_PROTOCOL': 'HTTP/1.1', 'SERVER_SOFTWARE': 'WSGIServer/0.1 Python/2.5.1', 'SHELL': '/bin/bash', 'SHLVL': '1', 'TERM': 'xterm-new', 'TERM_PROGRAM': 'iTerm.app', 'TZ': 'Europe/Zurich', 'USER': 'patricklauber', '_': '/usr/local/bin/python', '__CF_USER_TEXT_ENCODING': '0x1F5:0:0', 'wsgi.errors': <open file '<stderr>', mode 'w' at 0x130b0>, 'wsgi.file_wrapper': <class 'django.core.servers.basehttp.FileWrapper'>, 'wsgi.input': <socket._fileobject object at 0x1095f30>, 'wsgi.multiprocess': False, 'wsgi.multithread': True, 'wsgi.run_once': False, 'wsgi.url_scheme': 'http', 'wsgi.version': (1, 0)}>
      self 	
      <divio.middleware.stats.StatsMiddleware object at 0x22ae230>
      settings 	
      <django.conf.LazySettings object at 0xea590>
      start 	
      1188489635.296381
      view_args 	
      (u'courses', u'coursecollection', u'1')
      view_func 	
      <function _checklogin at 0x2301c30>
      view_kwargs 	
      {}
    * /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/django/contrib/admin/views/decorators.py in _checklogin
        48. def _checklogin(request, *args, **kwargs):
        49. if request.user.is_authenticated() and request.user.is_staff:
        50. # The user is valid. Continue to the admin page.
        51. if 'post_data' in request.POST:
        52. # User must have re-authenticated through a different window
        53. # or tab.
        54. request.POST = _decode_post_data(request.POST['post_data'])
        55. return view_func(request, *args, **kwargs) ...
        56.
        57. assert hasattr(request, 'session'), ""The Django admin requires session middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to insert 'django.contrib.sessions.middleware.SessionMiddleware'.""
        58.
        59. # If this isn't already the login page, display it.
        60. if LOGIN_FORM_KEY not in request.POST:
        61. if request.POST:
      ▶ Local vars
      Variable 	Value
      args 	
      (u'courses', u'coursecollection', u'1')
      kwargs 	
      {}
      request 	
      <WSGIRequest GET:<MultiValueDict: {}>, POST:<MultiValueDict: {u'info': [u'Bei ungen\xfcgender Anzahl Anmeldungen werden die Kurse koordiniert.'], u'course.0.location': [u'1'], u'course.0.examination_date': [u''], u'course.1.examination_date': [u''], u'prize': [u'590'], u'course.1.start_date': [u'2007-08-30'], u'days': [u'12'], u'course_type': [u'1'], u'course.1.coda': [u'dsf'], u'course.0.id': [u'1'], u'course.1.id': [u''], u'course.1.location': [u'1'], u'popup_text': [u'12 Kursabende 19.00 - 21.30 h / 19.15 - 21.45 h\r\nzus\xe4tzlich 1 ganzt\xe4giges Meteoseminar Basis'], u'course.0.coda': [u'dfs'], u'type': [u'0'], u'course.0.start_date': [u'2007-08-30']}>, COOKIES:{'sessionid': '02ec2573a0cb5bcda106515624beb12b'}, META:{'ADMINMEDIA': '/Users/patricklauber/Documents/workspace/divio.django/httpdocs/admin_media:', 'CONTENT_LENGTH': '453', 'CONTENT_TYPE': 'application/x-www-form-urlencoded', 'DJANGO_SETTINGS_MODULE': 'hoz.settings', 'GATEWAY_INTERFACE': 'CGI/1.1', 'HOME': '/Users/patricklauber', 'HTTP_ACCEPT': 'text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5', 'HTTP_ACCEPT_CHARSET': 'ISO-8859-1,utf-8;q=0.7,*;q=0.7', 'HTTP_ACCEPT_ENCODING': 'gzip,deflate', 'HTTP_ACCEPT_LANGUAGE': 'de-ch,de;q=0.8,en-us;q=0.5,en;q=0.3', 'HTTP_CONNECTION': 'keep-alive', 'HTTP_COOKIE': 'sessionid=02ec2573a0cb5bcda106515624beb12b', 'HTTP_HOST': 'localhost:8000', 'HTTP_KEEP_ALIVE': '300', 'HTTP_REFERER': 'http://localhost:8000/admin/courses/coursecollection/1/', 'HTTP_USER_AGENT': 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6', 'PATH': '/usr/local/Trolltech/Qt-4.3.0/bin:/Users/patricklauber/Documents/workspace/django/django/bin:/usr/local/mysql-5.0.37-osx10.4-i686/bin:/sw/bin:/usr/local/bin:/Library/Frameworks/Python.framework/Versions/Current/bin:/bin:/sbin:/usr/bin:/usr/sbin', 'PATH_INFO': '/admin/courses/coursecollection/1/', 'PWD': '/Users/patricklauber/Documents/workspace/html.hoz.ch/py_src/hoz', 'PYTHONPATH': '..:/Users/patricklauber/Documents/workspace/divio.django/src/:/Users/patricklauber/Documents/workspace/divio.django/src:', 'QUERY_STRING': '', 'REMOTE_ADDR': '127.0.0.1', 'REMOTE_HOST': '', 'REQUEST_METHOD': 'POST', 'RUN_MAIN': 'true', 'SCRIPT_NAME': '', 'SECURITYSESSIONID': 'b96da0', 'SERVER_NAME': 'localhost\r', 'SERVER_PORT': '8000', 'SERVER_PROTOCOL': 'HTTP/1.1', 'SERVER_SOFTWARE': 'WSGIServer/0.1 Python/2.5.1', 'SHELL': '/bin/bash', 'SHLVL': '1', 'TERM': 'xterm-new', 'TERM_PROGRAM': 'iTerm.app', 'TZ': 'Europe/Zurich', 'USER': 'patricklauber', '_': '/usr/local/bin/python', '__CF_USER_TEXT_ENCODING': '0x1F5:0:0', 'wsgi.errors': <open file '<stderr>', mode 'w' at 0x130b0>, 'wsgi.file_wrapper': <class 'django.core.servers.basehttp.FileWrapper'>, 'wsgi.input': <socket._fileobject object at 0x1095f30>, 'wsgi.multiprocess': False, 'wsgi.multithread': True, 'wsgi.run_once': False, 'wsgi.url_scheme': 'http', 'wsgi.version': (1, 0)}>
      view_func 	
      <function _wrapped_view_func at 0x2301bf0>
    * /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/django/views/decorators/cache.py in _wrapped_view_func
        32.
        33. def never_cache(view_func):
        34. """"""
        35. Decorator that adds headers to a response so that it will
        36. never be cached.
        37. """"""
        38. def _wrapped_view_func(request, *args, **kwargs):
        39. response = view_func(request, *args, **kwargs) ...
        40. add_never_cache_headers(response)
        41. return response
        42. return _wrapped_view_func
      ▶ Local vars
      Variable 	Value
      args 	
      (u'courses', u'coursecollection', u'1')
      kwargs 	
      {}
      request 	
      <WSGIRequest GET:<MultiValueDict: {}>, POST:<MultiValueDict: {u'info': [u'Bei ungen\xfcgender Anzahl Anmeldungen werden die Kurse koordiniert.'], u'course.0.location': [u'1'], u'course.0.examination_date': [u''], u'course.1.examination_date': [u''], u'prize': [u'590'], u'course.1.start_date': [u'2007-08-30'], u'days': [u'12'], u'course_type': [u'1'], u'course.1.coda': [u'dsf'], u'course.0.id': [u'1'], u'course.1.id': [u''], u'course.1.location': [u'1'], u'popup_text': [u'12 Kursabende 19.00 - 21.30 h / 19.15 - 21.45 h\r\nzus\xe4tzlich 1 ganzt\xe4giges Meteoseminar Basis'], u'course.0.coda': [u'dfs'], u'type': [u'0'], u'course.0.start_date': [u'2007-08-30']}>, COOKIES:{'sessionid': '02ec2573a0cb5bcda106515624beb12b'}, META:{'ADMINMEDIA': '/Users/patricklauber/Documents/workspace/divio.django/httpdocs/admin_media:', 'CONTENT_LENGTH': '453', 'CONTENT_TYPE': 'application/x-www-form-urlencoded', 'DJANGO_SETTINGS_MODULE': 'hoz.settings', 'GATEWAY_INTERFACE': 'CGI/1.1', 'HOME': '/Users/patricklauber', 'HTTP_ACCEPT': 'text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5', 'HTTP_ACCEPT_CHARSET': 'ISO-8859-1,utf-8;q=0.7,*;q=0.7', 'HTTP_ACCEPT_ENCODING': 'gzip,deflate', 'HTTP_ACCEPT_LANGUAGE': 'de-ch,de;q=0.8,en-us;q=0.5,en;q=0.3', 'HTTP_CONNECTION': 'keep-alive', 'HTTP_COOKIE': 'sessionid=02ec2573a0cb5bcda106515624beb12b', 'HTTP_HOST': 'localhost:8000', 'HTTP_KEEP_ALIVE': '300', 'HTTP_REFERER': 'http://localhost:8000/admin/courses/coursecollection/1/', 'HTTP_USER_AGENT': 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6', 'PATH': '/usr/local/Trolltech/Qt-4.3.0/bin:/Users/patricklauber/Documents/workspace/django/django/bin:/usr/local/mysql-5.0.37-osx10.4-i686/bin:/sw/bin:/usr/local/bin:/Library/Frameworks/Python.framework/Versions/Current/bin:/bin:/sbin:/usr/bin:/usr/sbin', 'PATH_INFO': '/admin/courses/coursecollection/1/', 'PWD': '/Users/patricklauber/Documents/workspace/html.hoz.ch/py_src/hoz', 'PYTHONPATH': '..:/Users/patricklauber/Documents/workspace/divio.django/src/:/Users/patricklauber/Documents/workspace/divio.django/src:', 'QUERY_STRING': '', 'REMOTE_ADDR': '127.0.0.1', 'REMOTE_HOST': '', 'REQUEST_METHOD': 'POST', 'RUN_MAIN': 'true', 'SCRIPT_NAME': '', 'SECURITYSESSIONID': 'b96da0', 'SERVER_NAME': 'localhost\r', 'SERVER_PORT': '8000', 'SERVER_PROTOCOL': 'HTTP/1.1', 'SERVER_SOFTWARE': 'WSGIServer/0.1 Python/2.5.1', 'SHELL': '/bin/bash', 'SHLVL': '1', 'TERM': 'xterm-new', 'TERM_PROGRAM': 'iTerm.app', 'TZ': 'Europe/Zurich', 'USER': 'patricklauber', '_': '/usr/local/bin/python', '__CF_USER_TEXT_ENCODING': '0x1F5:0:0', 'wsgi.errors': <open file '<stderr>', mode 'w' at 0x130b0>, 'wsgi.file_wrapper': <class 'django.core.servers.basehttp.FileWrapper'>, 'wsgi.input': <socket._fileobject object at 0x1095f30>, 'wsgi.multiprocess': False, 'wsgi.multithread': True, 'wsgi.run_once': False, 'wsgi.url_scheme': 'http', 'wsgi.version': (1, 0)}>
      view_func 	
      <function change_stage at 0x2301bb0>
    * /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/django/contrib/admin/views/main.py in change_stage
       325.
       326. if request.POST:
       327. new_data = request.POST.copy()
       328.
       329. if opts.has_field_type(models.FileField):
       330. new_data.update(request.FILES)
 331.
       332. errors = manipulator.get_validation_errors(new_data) ...
       333. manipulator.do_html2python(new_data)
       334.
       335. if not errors:
       336. new_object = manipulator.save(new_data)
       337. pk_value = new_object._get_pk_val()
 338.
      ▶ Local vars
      Variable 	Value
      app_label 	
      u'courses'
      manipulator 	
      <django.db.models.manipulators.ChangeManipulator object at 0x2303df0>
      model 	
      <class 'hoz.courses.models.CourseCollection'>
      model_name 	
      u'coursecollection'
      new_data 	
      <MultiValueDict: {u'info': [u'Bei ungen\xfcgender Anzahl Anmeldungen werden die Kurse koordiniert.'], u'course.0.location': [u'1'], u'course.0.examination_date': [u''], u'course.1.examination_date': [u''], u'course.1.start_date': [u'2007-08-30'], u'days': [u'12'], u'course_type': [u'1'], u'course.0.start_date': [u'2007-08-30'], u'course.1.coda': [u'dsf'], u'course.0.id': [u'1'], u'course.1.id': [u''], u'course.1.location': [u'1'], u'popup_text': [u'12 Kursabende 19.00 - 21.30 h / 19.15 - 21.45 h\r\nzus\xe4tzlich 1 ganzt\xe4giges Meteoseminar Basis'], u'course.0.coda': [u'dfs'], u'type': [u'0'], u'prize': [u'590']}>
      object_id 	
      u'1'
      opts 	
      <Options for CourseCollection>
      request 	
      <WSGIRequest GET:<MultiValueDict: {}>, POST:<MultiValueDict: {u'info': [u'Bei ungen\xfcgender Anzahl Anmeldungen werden die Kurse koordiniert.'], u'course.0.location': [u'1'], u'course.0.examination_date': [u''], u'course.1.examination_date': [u''], u'prize': [u'590'], u'course.1.start_date': [u'2007-08-30'], u'days': [u'12'], u'course_type': [u'1'], u'course.1.coda': [u'dsf'], u'course.0.id': [u'1'], u'course.1.id': [u''], u'course.1.location': [u'1'], u'popup_text': [u'12 Kursabende 19.00 - 21.30 h / 19.15 - 21.45 h\r\nzus\xe4tzlich 1 ganzt\xe4giges Meteoseminar Basis'], u'course.0.coda': [u'dfs'], u'type': [u'0'], u'course.0.start_date': [u'2007-08-30']}>, COOKIES:{'sessionid': '02ec2573a0cb5bcda106515624beb12b'}, META:{'ADMINMEDIA': '/Users/patricklauber/Documents/workspace/divio.django/httpdocs/admin_media:', 'CONTENT_LENGTH': '453', 'CONTENT_TYPE': 'application/x-www-form-urlencoded', 'DJANGO_SETTINGS_MODULE': 'hoz.settings', 'GATEWAY_INTERFACE': 'CGI/1.1', 'HOME': '/Users/patricklauber', 'HTTP_ACCEPT': 'text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5', 'HTTP_ACCEPT_CHARSET': 'ISO-8859-1,utf-8;q=0.7,*;q=0.7', 'HTTP_ACCEPT_ENCODING': 'gzip,deflate', 'HTTP_ACCEPT_LANGUAGE': 'de-ch,de;q=0.8,en-us;q=0.5,en;q=0.3', 'HTTP_CONNECTION': 'keep-alive', 'HTTP_COOKIE': 'sessionid=02ec2573a0cb5bcda106515624beb12b', 'HTTP_HOST': 'localhost:8000', 'HTTP_KEEP_ALIVE': '300', 'HTTP_REFERER': 'http://localhost:8000/admin/courses/coursecollection/1/', 'HTTP_USER_AGENT': 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6', 'PATH': '/usr/local/Trolltech/Qt-4.3.0/bin:/Users/patricklauber/Documents/workspace/django/django/bin:/usr/local/mysql-5.0.37-osx10.4-i686/bin:/sw/bin:/usr/local/bin:/Library/Frameworks/Python.framework/Versions/Current/bin:/bin:/sbin:/usr/bin:/usr/sbin', 'PATH_INFO': '/admin/courses/coursecollection/1/', 'PWD': '/Users/patricklauber/Documents/workspace/html.hoz.ch/py_src/hoz', 'PYTHONPATH': '..:/Users/patricklauber/Documents/workspace/divio.django/src/:/Users/patricklauber/Documents/workspace/divio.django/src:', 'QUERY_STRING': '', 'REMOTE_ADDR': '127.0.0.1', 'REMOTE_HOST': '', 'REQUEST_METHOD': 'POST', 'RUN_MAIN': 'true', 'SCRIPT_NAME': '', 'SECURITYSESSIONID': 'b96da0', 'SERVER_NAME': 'localhost\r', 'SERVER_PORT': '8000', 'SERVER_PROTOCOL': 'HTTP/1.1', 'SERVER_SOFTWARE': 'WSGIServer/0.1 Python/2.5.1', 'SHELL': '/bin/bash', 'SHLVL': '1', 'TERM': 'xterm-new', 'TERM_PROGRAM': 'iTerm.app', 'TZ': 'Europe/Zurich', 'USER': 'patricklauber', '_': '/usr/local/bin/python', '__CF_USER_TEXT_ENCODING': '0x1F5:0:0', 'wsgi.errors': <open file '<stderr>', mode 'w' at 0x130b0>, 'wsgi.file_wrapper': <class 'django.core.servers.basehttp.FileWrapper'>, 'wsgi.input': <socket._fileobject object at 0x1095f30>, 'wsgi.multiprocess': False, 'wsgi.multithread': True, 'wsgi.run_once': False, 'wsgi.url_scheme': 'http', 'wsgi.version': (1, 0)}>
    * /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/django/oldforms/__init__.py in get_validation_errors
        54. field.prepare(new_data)
        55.
        56. def get_validation_errors(self, new_data):
        57. ""Returns dictionary mapping field_names to error-message lists""
        58. errors = {}
        59. self.prepare(new_data)
        60. for field in self.fields:
        61. errors.update(field.get_validation_errors(new_data)) ...
        62. val_name = 'validate_%s' % field.field_name
        63. if hasattr(self, val_name):
        64. val = getattr(self, val_name)
        65. try:
        66. field.run_validator(new_data, val)
        67. except (validators.ValidationError, validators.CriticalValidationError), e:
      ▶ Local vars
      Variable 	Value
      errors 	
      {}
      field 	
      FormField ""course.0.coda""
      new_data 	
      <MultiValueDict: {u'info': [u'Bei ungen\xfcgender Anzahl Anmeldungen werden die Kurse koordiniert.'], u'course.0.location': [u'1'], u'course.0.examination_date': [u''], u'course.1.examination_date': [u''], u'course.1.start_date': [u'2007-08-30'], u'days': [u'12'], u'course_type': [u'1'], u'course.0.start_date': [u'2007-08-30'], u'course.1.coda': [u'dsf'], u'course.0.id': [u'1'], u'course.1.id': [u''], u'course.1.location': [u'1'], u'popup_text': [u'12 Kursabende 19.00 - 21.30 h / 19.15 - 21.45 h\r\nzus\xe4tzlich 1 ganzt\xe4giges Meteoseminar Basis'], u'course.0.coda': [u'dfs'], u'type': [u'0'], u'prize': [u'590']}>
      self 	
      <django.db.models.manipulators.ChangeManipulator object at 0x2303df0>
      val_name 	
      u'validate_course.0.id'
    * /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/django/oldforms/__init__.py in get_validation_errors
       371. errors = {}
       372. if self.is_required and not new_data.get(self.field_name, False):
       373. errors.setdefault(self.field_name, []).append(ugettext('This field is required.'))
       374. return errors
       375. try:
       376. for validator in self.validator_list:
       377. try:
       378. self.run_validator(new_data, validator) ...
       379. except validators.ValidationError, e:
       380. errors.setdefault(self.field_name, []).extend(e.messages)
       381. # If a CriticalValidationError is raised, ignore any other ValidationErrors
       382. # for this particular field
       383. except validators.CriticalValidationError, e:
       384. errors.setdefault(self.field_name, []).extend(e.messages)
      ▶ Local vars
      Variable 	Value
      errors 	
      {}
      new_data 	
      <MultiValueDict: {u'info': [u'Bei ungen\xfcgender Anzahl Anmeldungen werden die Kurse koordiniert.'], u'course.0.location': [u'1'], u'course.0.examination_date': [u''], u'course.1.examination_date': [u''], u'course.1.start_date': [u'2007-08-30'], u'days': [u'12'], u'course_type': [u'1'], u'course.0.start_date': [u'2007-08-30'], u'course.1.coda': [u'dsf'], u'course.0.id': [u'1'], u'course.1.id': [u''], u'course.1.location': [u'1'], u'popup_text': [u'12 Kursabende 19.00 - 21.30 h / 19.15 - 21.45 h\r\nzus\xe4tzlich 1 ganzt\xe4giges Meteoseminar Basis'], u'course.0.coda': [u'dfs'], u'type': [u'0'], u'prize': [u'590']}>
      self 	
      FormField ""course.0.coda""
      validator 	
      <function _curried at 0x2304270>
    * /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/django/oldforms/__init__.py in run_validator
       361.
       362.
       363. def run_validator(self, new_data, validator):
       364. if self.is_required or new_data.get(self.field_name, False) or hasattr(validator, 'always_test'):
       365. if hasattr(self, 'requires_data_list'):
       366. validator(new_data.getlist(self.field_name), new_data)
       367. else:
       368. validator(new_data.get(self.field_name, ''), new_data) ...
       369.
       370. def get_validation_errors(self, new_data):
       371. errors = {}
       372. if self.is_required and not new_data.get(self.field_name, False):
       373. errors.setdefault(self.field_name, []).append(ugettext('This field is required.'))
       374. return errors
      ▶ Local vars
      Variable 	Value
      new_data 	
      <MultiValueDict: {u'info': [u'Bei ungen\xfcgender Anzahl Anmeldungen werden die Kurse koordiniert.'], u'course.0.location': [u'1'], u'course.0.examination_date': [u''], u'course.1.examination_date': [u''], u'course.1.start_date': [u'2007-08-30'], u'days': [u'12'], u'course_type': [u'1'], u'course.0.start_date': [u'2007-08-30'], u'course.1.coda': [u'dsf'], u'course.0.id': [u'1'], u'course.1.id': [u''], u'course.1.location': [u'1'], u'popup_text': [u'12 Kursabende 19.00 - 21.30 h / 19.15 - 21.45 h\r\nzus\xe4tzlich 1 ganzt\xe4giges Meteoseminar Basis'], u'course.0.coda': [u'dfs'], u'type': [u'0'], u'prize': [u'590']}>
      self 	
      FormField ""course.0.coda""
      validator 	
      <function _curried at 0x2304270>
    * /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/django/utils/functional.py in _curried
         1. def curry(_curried_func, *args, **kwargs):
         2. def _curried(*moreargs, **morekwargs):
         3. return _curried_func(*(args+moreargs), **dict(kwargs, **morekwargs)) ...
         4. return _curried
         5.
         6. def memoize(func, cache, num_args):
         7. """"""
         8. Wrap a function so that results for any argument tuple are stored in
         9. 'cache'. Note that the args to the function must be usable as dictionary
      ▶ Local vars
      Variable 	Value
      _curried_func 	
      <function manipulator_validator_unique at 0x12b6530>
      args 	
      (<django.db.models.fields.CharField object at 0x224a1f0>, <Options for Course>, <django.db.models.manipulators.ChangeManipulator object at 0x2303df0>)
      kwargs 	
      {}
      moreargs 	
      (u'dfs', <MultiValueDict: {u'info': [u'Bei ungen\xfcgender Anzahl Anmeldungen werden die Kurse koordiniert.'], u'course.0.location': [u'1'], u'course.0.examination_date': [u''], u'course.1.examination_date': [u''], u'course.1.start_date': [u'2007-08-30'], u'days': [u'12'], u'course_type': [u'1'], u'course.0.start_date': [u'2007-08-30'], u'course.1.coda': [u'dsf'], u'course.0.id': [u'1'], u'course.1.id': [u''], u'course.1.location': [u'1'], u'popup_text': [u'12 Kursabende 19.00 - 21.30 h / 19.15 - 21.45 h\r\nzus\xe4tzlich 1 ganzt\xe4giges Meteoseminar Basis'], u'course.0.coda': [u'dfs'], u'type': [u'0'], u'prize': [u'590']}>)
      morekwargs 	
      {}
    * /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/django/db/models/fields/__init__.py in manipulator_validator_unique
        37. class FieldDoesNotExist(Exception):
        38. pass
        39.
        40. def manipulator_validator_unique(f, opts, self, field_data, all_data):
        41. ""Validates that the value is unique for this field.""
        42. lookup_type = f.get_validator_unique_lookup_type()
        43. try:
        44. old_obj = self.manager.get(**{lookup_type: field_data}) ...
        45. except ObjectDoesNotExist:
        46. return
        47. if getattr(self, 'original_object', None) and self.original_object._get_pk_val() == old_obj._get_pk_val():
        48. return
        49. raise validators.ValidationError, _(""%(optname)s with this %(fieldname)s already exists."") % {'optname': capfirst(opts.verbose_name), 'fieldname': f.verbose_name}
  50.
      ▶ Local vars
      Variable 	Value
      all_data 	
      <MultiValueDict: {u'info': [u'Bei ungen\xfcgender Anzahl Anmeldungen werden die Kurse koordiniert.'], u'course.0.location': [u'1'], u'course.0.examination_date': [u''], u'course.1.examination_date': [u''], u'course.1.start_date': [u'2007-08-30'], u'days': [u'12'], u'course_type': [u'1'], u'course.0.start_date': [u'2007-08-30'], u'course.1.coda': [u'dsf'], u'course.0.id': [u'1'], u'course.1.id': [u''], u'course.1.location': [u'1'], u'popup_text': [u'12 Kursabende 19.00 - 21.30 h / 19.15 - 21.45 h\r\nzus\xe4tzlich 1 ganzt\xe4giges Meteoseminar Basis'], u'course.0.coda': [u'dfs'], u'type': [u'0'], u'prize': [u'590']}>
      f 	
      <django.db.models.fields.CharField object at 0x224a1f0>
      field_data 	
      u'dfs'
      lookup_type 	
      u'coda__exact'
      opts 	
      <Options for Course>
      self 	
      <django.db.models.manipulators.ChangeManipulator object at 0x2303df0>
    * /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/django/db/models/manager.py in get
        62. def distinct(self, *args, **kwargs):
        63. return self.get_query_set().distinct(*args, **kwargs)
        64.
        65. def extra(self, *args, **kwargs):
        66. return self.get_query_set().extra(*args, **kwargs)
        67.
        68. def get(self, *args, **kwargs):
        69. return self.get_query_set().get(*args, **kwargs) ...
        70.
        71. def get_or_create(self, **kwargs):
        72. return self.get_query_set().get_or_create(**kwargs)
        73.
        74. def create(self, **kwargs):
        75. return self.get_query_set().create(**kwargs)
      ▶ Local vars
      Variable 	Value
      args 	
      ()
      kwargs 	
      {'coda__exact': u'dfs'}
      self 	
      <django.db.models.manager.Manager object at 0x224a290>
    * /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/django/db/models/query.py in get
       253.
       254. def get(self, *args, **kwargs):
       255. ""Performs the SELECT and returns a single object matching the given keyword arguments.""
       256. clone = self.filter(*args, **kwargs)
       257. # clean up SQL by removing unneeded ORDER BY
       258. if not clone._order_by:
       259. clone._order_by = ()
       260. obj_list = list(clone) ...
       261. if len(obj_list) < 1:
       262. raise self.model.DoesNotExist, ""%s matching query does not exist."" % self.model._meta.object_name
       263. assert len(obj_list) == 1, ""get() returned more than one %s -- it returned %s! Lookup parameters were %s"" % (self.model._meta.object_name, len(obj_list), kwargs)
       264. return obj_list[0]
       265.
       266. def create(self, **kwargs):
      ▶ Local vars
      Variable 	Value
      args 	
      ()
      clone 	
      Error in formatting: Cannot resolve keyword 'coda' into field. Choices are: course, id, course_type, type, days, popup_text, info, prize
      kwargs 	
      {'coda__exact': u'dfs'}
      self 	
      [<CourseCollection: Hochseescheinkurse in der Schweiz(0)>]
    * /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/django/db/models/query.py in __iter__
       106. def __repr__(self):
       107. return repr(self._get_data())
       108.
       109. def __len__(self):
       110. return len(self._get_data())
       111.
       112. def __iter__(self):
       113. return iter(self._get_data()) ...
       114.
       115. def __getitem__(self, k):
       116. ""Retrieve an item or slice from the set of results.""
       117. if not isinstance(k, (slice, int, long)):
       118. raise TypeError
       119. assert (not isinstance(k, slice) and (k >= 0)) \
      ▶ Local vars
      Variable 	Value
      self 	
      Error in formatting: Cannot resolve keyword 'coda' into field. Choices are: course, id, course_type, type, days, popup_text, info, prize
    * /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/django/db/models/query.py in _get_data
       473. if (self._order_by is not None and len(self._order_by) > 0) and \
       474. (combined._order_by is None or len(combined._order_by) == 0):
       475. combined._order_by = self._order_by
       476. return combined
       477.
       478. def _get_data(self):
       479. if self._result_cache is None:
       480. self._result_cache = list(self.iterator()) ...
       481. return self._result_cache
       482.
       483. def _get_sql_clause(self):
       484. opts = self.model._meta
       485.
       486. # Construct the fundamental parts of the query: SELECT X FROM Y WHERE Z.
      ▶ Local vars
      Variable 	Value
      self 	
      Error in formatting: Cannot resolve keyword 'coda' into field. Choices are: course, id, course_type, type, days, popup_text, info, prize
    * /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/django/db/models/query.py in iterator
       172. ####################################
       173. # METHODS THAT DO DATABASE QUERIES #
       174. ####################################
       175.
       176. def iterator(self):
       177. ""Performs the SELECT database lookup of this QuerySet.""
       178. try:
       179. select, sql, params = self._get_sql_clause() ...
       180. except EmptyResultSet:
       181. raise StopIteration
       182.
       183. # self._select is a dictionary, and dictionaries' key order is
       184. # undefined, so we convert it to a list of tuples.
       185. extra_select = self._select.items()
      ▶ Local vars
      Variable 	Value
      self 	
      Error in formatting: Cannot resolve keyword 'coda' into field. Choices are: course, id, course_type, type, days, popup_text, info, prize
    * /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/django/db/models/query.py in _get_sql_clause
       487. select = [""%s.%s"" % (backend.quote_name(opts.db_table), backend.quote_name(f.column)) for f in opts.fields]
       488. tables = [quote_only_if_word(t) for t in self._tables]
       489. joins = SortedDict()
       490. where = self._where[:]
       491. params = self._params[:]
       492.
       493. # Convert self._filters into SQL.
       494. joins2, where2, params2 = self._filters.get_sql(opts) ...
       495. joins.update(joins2)
       496. where.extend(where2)
       497. params.extend(params2)
       498.
       499. # Add additional tables and WHERE clauses based on select_related.
       500. if self._select_related:
      ▶ Local vars
      Variable 	Value
      f 	
      <django.db.models.fields.PositiveSmallIntegerField object at 0x2254c30>
      joins 	
      {}
      opts 	
      <Options for CourseCollection>
      params 	
      []
      select 	
      ['`courses_coursecollection`.`id`', '`courses_coursecollection`.`course_type_id`', '`courses_coursecollection`.`type`', '`courses_coursecollection`.`days`', '`courses_coursecollection`.`popup_text`', '`courses_coursecollection`.`info`', '`courses_coursecollection`.`prize`']
      self 	
      Error in formatting: Cannot resolve keyword 'coda' into field. Choices are: course, id, course_type, type, days, popup_text, info, prize
      tables 	
      []
      where 	
      []
    * /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/django/db/models/query.py in get_sql
       706. def __init__(self, *args):
       707. self.args = args
       708.
       709. def get_sql(self, opts):
       710. joins, where, params = SortedDict(), [], []
       711. for val in self.args:
       712. try:
       713. joins2, where2, params2 = val.get_sql(opts) ...
       714. joins.update(joins2)
       715. where.extend(where2)
       716. params.extend(params2)
       717. except EmptyResultSet:
       718. if not isinstance(self, QOr):
       719. raise EmptyResultSet
      ▶ Local vars
      Variable 	Value
      joins 	
      {}
      joins2 	
      {}
      opts 	
      <Options for CourseCollection>
      params 	
      []
      params2 	
      []
      self 	
      <django.db.models.query.QAnd object at 0x231a0f0>
      val 	
      <django.db.models.query.Q object at 0x231a0d0>
      where 	
      []
      where2 	
      []
    * /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/django/db/models/query.py in get_sql
       757. def __and__(self, other):
       758. return QAnd(self, other)
       759.
       760. def __or__(self, other):
       761. return QOr(self, other)
       762.
       763. def get_sql(self, opts):
       764. return parse_lookup(self.kwargs.items(), opts) ...
       765.
       766. class QNot(Q):
       767. ""Encapsulates NOT (...) queries as objects""
       768. def __init__(self, q):
       769. ""Creates a negation of the q object passed in.""
       770. self.q = q
      ▶ Local vars
      Variable 	Value
      opts 	
      <Options for CourseCollection>
      self 	
      <django.db.models.query.Q object at 0x231a0d0>
    * /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/django/db/models/query.py in parse_lookup
       914. # Interpret '__exact=None' as the sql '= NULL'; otherwise, reject
       915. # all uses of None as a query value.
       916. if lookup_type != 'exact':
       917. raise ValueError, ""Cannot use None as a query value""
       918. elif callable(value):
       919. value = value()
 920.
       921. joins2, where2, params2 = lookup_inner(path, lookup_type, value, opts, opts.db_table, None) ...
       922. joins.update(joins2)
       923. where.extend(where2)
       924. params.extend(params2)
       925. return joins, where, params
       926.
       927. class FieldFound(Exception):
      ▶ Local vars
      Variable 	Value
      joins 	
      {}
      kwarg 	
      u'coda__exact'
      kwarg_items 	
      [('coda__exact', u'dfs')]
      lookup_type 	
      u'exact'
      opts 	
      <Options for CourseCollection>
      params 	
      []
      path 	
      []
      value 	
      u'dfs'
      where 	
      []
    * /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/django/db/models/query.py in lookup_inner
      1032. except FieldFound: # Match found, loop has been shortcut.
      1033. pass
      1034. else: # No match found.
      1035. choices = field_choices(current_opts.many_to_many, False) + \
      1036. field_choices(current_opts.get_all_related_many_to_many_objects(), True) + \
      1037. field_choices(current_opts.get_all_related_objects(), True) + \
      1038. field_choices(current_opts.fields, False)
      1039. raise TypeError, ""Cannot resolve keyword '%s' into field. Choices are: %s"" % (name, "", "".join(choices)) ...
      1040.
      1041. # Check whether an intermediate join is required between current_table
      1042. # and new_table.
      1043. if intermediate_table:
      1044. joins[qn(current_table)] = (
      1045. qn(intermediate_table), ""LEFT OUTER JOIN"",
      ▶ Local vars 

}}}"		closed	contrib.admin	dev		duplicate	unique,edit_inline	patrick.lauber@…	Unreviewed	0	0	0	0	0	0
