#29701: has_add_permission in admin.TabularInline gives KeyError exception
-------------------------------+--------------------------------------
Reporter: Harm Verhagen | Owner: nobody
Type: Bug | Status: new
Component: contrib.admin | Version: 2.1
Severity: Normal | Resolution:
Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------+--------------------------------------
Description changed by Harm Verhagen:
Old description:
> I noticed that using {{{has_add_permission()}}} on a
> {{{admin.TabularInline}}} fails.
>
> See the simple example below.
>
> h3. steps to reproduce
>
> models.py
> {{{
> class ModelA(models.Model):
> name = models.CharField(max_length=2)
> bs = models.ManyToManyField("ModelB", through="Through")
>
> def __str__(self):
> return "%s" % self.name
>
> class ModelB(models.Model):
> name = models.CharField(max_length=2)
>
> def __str__(self):
> return "%s" % self.name
>
> class Through(models.Model):
> a = models.ForeignKey(ModelA, on_delete=models.CASCADE)
> b = models.ForeignKey(ModelB, on_delete=models.CASCADE)
>
> def __str__(self):
> return "%s-%s" % (self.a, self.b)
> }}}
>
> admin.py
> {{{
> class ThroughInline(admin.TabularInline):
>
> model = Through
>
> def has_add_permission(self, request, obj):
> # setting this to False results in an error
> return False
>
> class ModelAAdmin(admin.ModelAdmin):
> inlines = (ThroughInline, )
>
> class ModelBAdmin(admin.ModelAdmin):
> inlines = (ThroughInline, )
>
> class ThroughAdmin(admin.ModelAdmin):
> pass
> }}}
>
> Then create your objects.
> {{{
> >>> from <yourapp>.models import ModelA, ModelB, Through
> >>> a = ModelA.objects.create(name='a')
> >>> b= ModelB.objects.create(name='b')
> >>> t = Through.objects.create(a=a, b=b)
> }}}
>
> Fire up a runserver and visit the admin api:
> http://localhost:8000/admin/<yourapp>/modela/1/change/
>
> h3. result
>
> A server 500
> {{{
> KeyError at /admin/<appname>/modela/1/change/
>
> Request Method: GET
> Request URL: http://localhost:8000/admin/<appname>/modela/1/change/
> Django Version: 2.1
> Exception Type: KeyError
> Exception Value: 'b'
>
> Template error:
> In template ...contrib/admin/templates/admin/edit_inline/tabular.html,
> error at line 13
> b
> 3 : data-inline-type="tabular"
> 4 : data-inline-formset="{{
> inline_admin_formset.inline_formset_data }}">
> 5 : <div class="tabular inline-related {% if forloop.last %}last-
> related{% endif %}">
> 6 : {{ inline_admin_formset.formset.management_form }}
> 7 : <fieldset class="module {{ inline_admin_formset.classes }}">
> 8 : <h2>{{ inline_admin_formset.opts.verbose_name_plural|capfirst
> }}</h2>
> 9 : {{ inline_admin_formset.formset.non_form_errors }}
> 10 : <table>
> 11 : <thead><tr>
> 12 : <th class="original"></th>
> 13 : {% for field in inline_admin_formset.fields %}
> 14 : {% if not field.widget.is_hidden %}
> 15 : <th{% if field.required %} class="required"{% endif
> %}>{{ field.label|capfirst }}
> 16 : {% if field.help_text %} <img src="{% static
> "admin/img/icon-unknown.svg" %}" class="help help-tooltip" width="10"
> height="10" alt="({{ field.help_text|striptags }})" title="{{
> field.help_text|striptags }}">{% endif %}
> 17 : </th>
> 18 : {% endif %}
> 19 : {% endfor %}
> 20 : {% if inline_admin_formset.formset.can_delete %}<th>{% trans
> "Delete?" %}</th>{% endif %}
> 21 : </tr></thead>
> 22 :
> 23 : <tbody>
>
> Traceback:
>
> File "/venv3/lib/python3.5/site-
> packages/django/core/handlers/exception.py" in inner
> 34. response = get_response(request)
>
> File "/venv3/lib/python3.5/site-packages/django/core/handlers/base.py" in
> _get_response
> 156. response = self.process_exception_by_middleware(e,
> request)
>
> File "/venv3/lib/python3.5/site-packages/django/core/handlers/base.py" in
> _get_response
> 154. response = response.render()
>
> File "/venv3/lib/python3.5/site-packages/django/template/response.py" in
> render
> 106. self.content = self.rendered_content
>
> File "/venv3/lib/python3.5/site-packages/django/template/response.py" in
> rendered_content
> 83. content = template.render(context, self._request)
>
> }}}
>
> h3. expected result
>
> The inlines are displayed without the option to create new Through
> instances.
>
> h3. version
> {{{Django==2.1}}}
New description:
I noticed that using {{{has_add_permission()}}} on a
{{{admin.TabularInline}}} fails.
See the simple example below.
=== steps to reproduce
models.py
{{{
class ModelA(models.Model):
name = models.CharField(max_length=2)
bs = models.ManyToManyField("ModelB", through="Through")
def __str__(self):
return "%s" % self.name
class ModelB(models.Model):
name = models.CharField(max_length=2)
def __str__(self):
return "%s" % self.name
class Through(models.Model):
a = models.ForeignKey(ModelA, on_delete=models.CASCADE)
b = models.ForeignKey(ModelB, on_delete=models.CASCADE)
def __str__(self):
return "%s-%s" % (self.a, self.b)
}}}
admin.py
{{{
class ThroughInline(admin.TabularInline):
model = Through
def has_add_permission(self, request, obj):
# setting this to False results in an error
return False
class ModelAAdmin(admin.ModelAdmin):
inlines = (ThroughInline, )
class ModelBAdmin(admin.ModelAdmin):
inlines = (ThroughInline, )
class ThroughAdmin(admin.ModelAdmin):
pass
}}}
Then create your objects.
{{{
>>> from <yourapp>.models import ModelA, ModelB, Through
>>> a = ModelA.objects.create(name='a')
>>> b= ModelB.objects.create(name='b')
>>> t = Through.objects.create(a=a, b=b)
}}}
Fire up a runserver and visit the admin api:
http://localhost:8000/admin/<yourapp>/modela/1/change/
=== result
A server 500
{{{
KeyError at /admin/<appname>/modela/1/change/
Request Method: GET
Request URL: http://localhost:8000/admin/<appname>/modela/1/change/
Django Version: 2.1
Exception Type: KeyError
Exception Value: 'b'
Template error:
In template ...contrib/admin/templates/admin/edit_inline/tabular.html,
error at line 13
b
3 : data-inline-type="tabular"
4 : data-inline-formset="{{
inline_admin_formset.inline_formset_data }}">
5 : <div class="tabular inline-related {% if forloop.last %}last-
related{% endif %}">
6 : {{ inline_admin_formset.formset.management_form }}
7 : <fieldset class="module {{ inline_admin_formset.classes }}">
8 : <h2>{{ inline_admin_formset.opts.verbose_name_plural|capfirst
}}</h2>
9 : {{ inline_admin_formset.formset.non_form_errors }}
10 : <table>
11 : <thead><tr>
12 : <th class="original"></th>
13 : {% for field in inline_admin_formset.fields %}
14 : {% if not field.widget.is_hidden %}
15 : <th{% if field.required %} class="required"{% endif %}>{{
field.label|capfirst }}
16 : {% if field.help_text %} <img src="{% static
"admin/img/icon-unknown.svg" %}" class="help help-tooltip" width="10"
height="10" alt="({{ field.help_text|striptags }})" title="{{
field.help_text|striptags }}">{% endif %}
17 : </th>
18 : {% endif %}
19 : {% endfor %}
20 : {% if inline_admin_formset.formset.can_delete %}<th>{% trans
"Delete?" %}</th>{% endif %}
21 : </tr></thead>
22 :
23 : <tbody>
Traceback:
File "/venv3/lib/python3.5/site-
packages/django/core/handlers/exception.py" in inner
34. response = get_response(request)
File "/venv3/lib/python3.5/site-packages/django/core/handlers/base.py" in
_get_response
156. response = self.process_exception_by_middleware(e,
request)
File "/venv3/lib/python3.5/site-packages/django/core/handlers/base.py" in
_get_response
154. response = response.render()
File "/venv3/lib/python3.5/site-packages/django/template/response.py" in
render
106. self.content = self.rendered_content
File "/venv3/lib/python3.5/site-packages/django/template/response.py" in
rendered_content
83. content = template.render(context, self._request)
}}}
=== expected result
The inlines are displayed without the option to create new Through
instances.
=== version
{{{Django==2.1}}}
--
--
Ticket URL: <https://code.djangoproject.com/ticket/29701#comment:2>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/063.57ace41876facf68ad9f030fa8d57155%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.