Has_delete_permission gets parent instance in django admin inline

I have a reservation model with a foreign user key. In the administrator, orders are embedded in the user change page.

I want some orders not to be deleted (from the built-in) when there are less than 24 hours left until the reservation, and the registered user is not included in the SuperStaff group.

So, I define BookingInline something like this:

class BookingInline(admin.TabularInline): model = Booking extra = 0 fk_name = 'bookedFor' def has_delete_permission(self, request, obj=None): if not request.user.profile.isSuperStaff() and obj.is24hoursFromNow(): return True return False 

This code has been reached, but I get the userโ€™s copy, not the reservation number (and an error, of course), so I canโ€™t decide for each individual reservation if it can be deleted or not. Is the has_delete_permission () method supposed to get an instance of the inline object in this case? There is nothing in django docs ...

I know that the code has been reached since I checked it using only the condition for the user, and it actually hides the delete window for the corresponding users.

I also tried to do it differently using the Formset and clean () method, but it does not have the request parameter, so I get the required instance, but not the user logged in.

I have been looking for a solution for several hours, but it seems that the only way is to put a link from the built-in page with a complete change to the Booking object and check the permissions when the user tries to delete the Booking regularly.

Any ideas how this can be done in an elegant way will be appreciated.

+5
source share
1 answer

Today I had the same problem, and I think I found an acceptable way to solve it. Here is what I did:

I needed to make inlines deleted only if a certain field had a certain value. In particular, since I am dealing with generic tasks and assignments, only missed tasks should be deleted. In terms of the model:

 class Task(models.Model): STATUS_CHOICES = ( ('PND', 'Pending'), ('ACC', 'Accepted'), ) status = models.CharField( ----> If this != 'PND', inline instance max_length=3, should not be deletable choices=STATUS_CHOICES, default=STATUS_CHOICES[0][0]) 

Since I could not use has_delete_permission in my admin.TabularInline class, since this applies to the entire set of fields (i.e. to all built-in lines), and not to a single line, I went through the pattern override path:

tabular.html: 44-62 (original)

 [...] {% for fieldset in inline_admin_form %} {% for line in fieldset %} {% for field in line %} {% if not field.field.is_hidden %} <td{% if field.field.name %} class="field-{{ field.field.name }}"{% endif %}> {% if field.is_readonly %} <p>{{ field.contents }}</p> {% else %} {{ field.field.errors.as_ul }} {{ field.field }} {% endif %} </td> {% endif %} {% endfor %} {% endfor %} {% endfor %} {% if inline_admin_formset.formset.can_delete %} <td class="delete">{% if inline_admin_form.original %}{{ inline_admin_form.deletion_field.field }}{% endif %}</td> {% endif %} [...] 

tabular.html (overridden)

 [...] {% for fieldset in inline_admin_form %} {% for line in fieldset %} {% for field in line %} {% if not field.field.is_hidden %} <td{% if field.field.name %} class="field-{{ field.field.name }}"{% endif %}> {% if field.is_readonly %} <p>{{ field.contents }}</p> {% else %} {% include "admin/includes/field.html" with is_tabular=True %} {% endif %} </td> {% endif %} {% endfor %} {% endfor %} <!-- Custom deletion logic, only available for non-accepted objects --> {% for line in fieldset %} {% for field in line %} {% if field.field.name == "status" %} {% if field.field.value == "PND" %} <td class="delete">{% if inline_admin_form.original %}{{ inline_admin_form.deletion_field.field }}{% endif %}</td> {% else %} <td class="delete"><input type="checkbox" disabled="disabled"> <img src="/static/admin/img/icon_alert.gif" data-toggle="tooltip" class="title-starter" data-original-title="Can't remove accepted tasks" /> </td> {% endif %} {% endif %} {% endfor %} {% endfor %} {% endfor %} <!-- Classic deletion, removed {% if inline_admin_formset.formset.can_delete %} <td class="delete">{% if inline_admin_form.original %}{{ inline_admin_form.deletion_field.field }}{% endif %}</td> {% endif %} --> [...] 

As a result (non-standard graphics, as I use django-admin-bootstrap ):

enter image description here

Strictly speaking of "elegance," I have to go through the line fields twice to make it work, but I have not found a better way than reading this field value directly. I could not have anything like {{ line.fields.0.status }} or {{ line.fields.status }} . If anyone could point to direct syntax, I would gladly update my solution.

In any case, since it still works, and itโ€™s not so bad, I will be fine with this method until nothing works better.

+3
source

Source: https://habr.com/ru/post/1211845/


All Articles