-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SIANXKE-380: prepare option to disable single attachments in inline #15
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -66,6 +66,46 @@ class PhotoAlbumAdmin(admin.ModelAdmin): | |||||
`ReadOnlyAttachmentInlineAdmin` is useful when attachments should be provided only by REST API. You may consider | ||||||
extending the classes in order to handle additional permission checks. | ||||||
|
||||||
The package provides a custom `DynamicallyDisabledAttachmentInlineForm` that allows disablement (setting readonly) of | ||||||
single attachments depending on its `disable_inline_fields` method. Override it to define your own logic to decide when | ||||||
an inline attachment should not be editable. | ||||||
In addition to that a custom `DynamicallyDisabledAttachmentInlineFormSet` class can also disable the DELETE checkbox | ||||||
of single attachments. | ||||||
|
||||||
Example usage: | ||||||
``` | ||||||
# customize the DynamicallyDisabledAttachmentInlineForm to determine which inline attachments should be readonly | ||||||
MyCustomDynamicallyDisabledAttachmentInlineForm(DynamicallyDisabledAttachmentInlineForm): | ||||||
def disable_inline_fields(self): | ||||||
""" | ||||||
Attachments with context IMMUTABLE should be disabled / readonly | ||||||
""" | ||||||
return self.instance and self.instance.context == "IMMUTABLE" | ||||||
|
||||||
|
||||||
# customize the DynamicallyDisabledAttachmentInlineFormSet to determine which inline attachments' DELETE checkbox | ||||||
# should be readonly | ||||||
MyCustomDynamicallyDisabledAttachmentInlineFormSet(DynamicallyDisabledAttachmentInlineFormSet): | ||||||
super().add_fields(form, index) | ||||||
""" | ||||||
DELETE checkbox for Attachments that return True for | ||||||
MyCustomDynamicallyDisabledAttachmentInlineForm's disable_inline_fields method should be disabled | ||||||
""" | ||||||
if hasattr(form, 'disable_inline_fields') and form.disable_inline_fields(): | ||||||
form.fields['DELETE'].disabled = True | ||||||
|
||||||
|
||||||
class MyCustomDynamicallyDisabledAttachmentInlineAdmin(AttachmentInlineAdmin): | ||||||
form = MyCustomDynamicallyDisabledAttachmentInlineForm | ||||||
formset = MyCustomDynamicallyDisabledAttachmentInlineFormSet | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
def has_add_permission(self, request, obj=None): | ||||||
return False | ||||||
|
||||||
show_change_link = False | ||||||
``` | ||||||
|
||||||
|
||||||
## Usage with DRF (ToDo: API needs to be simplified) | ||||||
|
||||||
|
||||||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,9 +1,9 @@ | ||||||||||||||||||||||||||||||||||||||||
from content_disposition import rfc5987_content_disposition | ||||||||||||||||||||||||||||||||||||||||
from django.contrib import admin | ||||||||||||||||||||||||||||||||||||||||
from django.contrib.admin import AdminSite | ||||||||||||||||||||||||||||||||||||||||
from django.contrib.admin.views.decorators import staff_member_required | ||||||||||||||||||||||||||||||||||||||||
from django.contrib.contenttypes.admin import GenericTabularInline | ||||||||||||||||||||||||||||||||||||||||
from django.contrib.contenttypes.forms import BaseGenericInlineFormSet | ||||||||||||||||||||||||||||||||||||||||
from django.forms import ChoiceField, ModelForm | ||||||||||||||||||||||||||||||||||||||||
from django.forms.utils import ErrorList | ||||||||||||||||||||||||||||||||||||||||
from django.http import StreamingHttpResponse | ||||||||||||||||||||||||||||||||||||||||
from django.urls import NoReverseMatch, path, reverse | ||||||||||||||||||||||||||||||||||||||||
from django.utils.safestring import mark_safe | ||||||||||||||||||||||||||||||||||||||||
|
@@ -117,6 +117,65 @@ def download_view(self, request, object_id): | |||||||||||||||||||||||||||||||||||||||
return response | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
class DynamicallyDisabledAttachmentInlineForm(AttachmentForm): | ||||||||||||||||||||||||||||||||||||||||
class Meta: | ||||||||||||||||||||||||||||||||||||||||
model = Attachment | ||||||||||||||||||||||||||||||||||||||||
fields = "__all__" | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
def disable_inline_fields(self): | ||||||||||||||||||||||||||||||||||||||||
""" | ||||||||||||||||||||||||||||||||||||||||
Override to return True/False when custom condition is met | ||||||||||||||||||||||||||||||||||||||||
and change field readonly status in inline admin list on True | ||||||||||||||||||||||||||||||||||||||||
""" | ||||||||||||||||||||||||||||||||||||||||
raise NotImplementedError() | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
def __init__( | ||||||||||||||||||||||||||||||||||||||||
self, | ||||||||||||||||||||||||||||||||||||||||
data=None, | ||||||||||||||||||||||||||||||||||||||||
files=None, | ||||||||||||||||||||||||||||||||||||||||
auto_id="id_%s", | ||||||||||||||||||||||||||||||||||||||||
prefix=None, | ||||||||||||||||||||||||||||||||||||||||
initial=None, | ||||||||||||||||||||||||||||||||||||||||
error_class=ErrorList, | ||||||||||||||||||||||||||||||||||||||||
label_suffix=None, | ||||||||||||||||||||||||||||||||||||||||
empty_permitted=False, | ||||||||||||||||||||||||||||||||||||||||
instance=None, | ||||||||||||||||||||||||||||||||||||||||
use_required_attribute=None, | ||||||||||||||||||||||||||||||||||||||||
renderer=None, | ||||||||||||||||||||||||||||||||||||||||
): | ||||||||||||||||||||||||||||||||||||||||
super().__init__( | ||||||||||||||||||||||||||||||||||||||||
data, | ||||||||||||||||||||||||||||||||||||||||
files, | ||||||||||||||||||||||||||||||||||||||||
auto_id, | ||||||||||||||||||||||||||||||||||||||||
prefix, | ||||||||||||||||||||||||||||||||||||||||
initial, | ||||||||||||||||||||||||||||||||||||||||
error_class, | ||||||||||||||||||||||||||||||||||||||||
label_suffix, | ||||||||||||||||||||||||||||||||||||||||
empty_permitted, | ||||||||||||||||||||||||||||||||||||||||
instance, | ||||||||||||||||||||||||||||||||||||||||
use_required_attribute, | ||||||||||||||||||||||||||||||||||||||||
renderer, | ||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
# make all fields of the inline attachment read only | ||||||||||||||||||||||||||||||||||||||||
if self.disable_inline_fields(): | ||||||||||||||||||||||||||||||||||||||||
for field in self.fields: | ||||||||||||||||||||||||||||||||||||||||
self.fields[field].disabled = True | ||||||||||||||||||||||||||||||||||||||||
Comment on lines
+161
to
+163
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Setting Sadly, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's true, that the checkbox is still available, but on usage the form will render a corresponding error message and prevent the deletion. I think that is OK. Another option would be to use a custom FormSet where the checkbox is simply disabled - I'll look into a way to combine this with the current approach. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I almost spat out my coffee when I saw the |
||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
class DynamicallyDisabledAttachmentInlineFormSet(BaseGenericInlineFormSet): | ||||||||||||||||||||||||||||||||||||||||
def add_fields(self, form, index): | ||||||||||||||||||||||||||||||||||||||||
""" | ||||||||||||||||||||||||||||||||||||||||
Override to disable the DELETE checkbox of entries matching a specific custom condition. | ||||||||||||||||||||||||||||||||||||||||
E.g. to make this dependent of the DynamicallyDisabledAttachmentInlineForm's disable_inline_fields method: | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
super().add_fields(form, index) | ||||||||||||||||||||||||||||||||||||||||
if hasattr(form, 'disable_inline_fields') and form.disable_inline_fields(): | ||||||||||||||||||||||||||||||||||||||||
form.fields['DELETE'].disabled = True | ||||||||||||||||||||||||||||||||||||||||
""" | ||||||||||||||||||||||||||||||||||||||||
raise NotImplementedError() | ||||||||||||||||||||||||||||||||||||||||
Comment on lines
+166
to
+176
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we inherit from this and use
Suggested change
|
||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
class BaseAttachmentInlineAdmin(GenericTabularInline, AttachmentAdminMixin): | ||||||||||||||||||||||||||||||||||||||||
model = Attachment | ||||||||||||||||||||||||||||||||||||||||
form = AttachmentForm | ||||||||||||||||||||||||||||||||||||||||
|
@@ -129,12 +188,14 @@ class BaseAttachmentInlineAdmin(GenericTabularInline, AttachmentAdminMixin): | |||||||||||||||||||||||||||||||||||||||
"mime_type", | ||||||||||||||||||||||||||||||||||||||||
"extension", | ||||||||||||||||||||||||||||||||||||||||
"creation_date", | ||||||||||||||||||||||||||||||||||||||||
"last_modification_date", | ||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||
readonly_fields = ( | ||||||||||||||||||||||||||||||||||||||||
"size", | ||||||||||||||||||||||||||||||||||||||||
"mime_type", | ||||||||||||||||||||||||||||||||||||||||
"extension", | ||||||||||||||||||||||||||||||||||||||||
"creation_date", | ||||||||||||||||||||||||||||||||||||||||
"last_modification_date", | ||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With the already implemented code in
DynamicallyDisabledAttachmentInlineFormSet
this part could be removed.