#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
> {code}
> 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)
> {code}
>
> admin.py
> {code}
> 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
> {code}
>
> Then create your objects.
> {code}
> >>> 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)
> {code}
>
> Fire up a runserver and visit the admin api:
> http://localhost:8000/admin/<yourapp>/modela/1/change/
>
> h3. result
>
> A server 500
> {code}
> 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 %}&nbsp;<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)
>
> {code}
>
> 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.

 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 %}&nbsp;<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}}}

--

-- 
Ticket URL: <https://code.djangoproject.com/ticket/29701#comment:1>
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.9897c989bafe8398d331190d9f8ccab8%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to