Skip to content

Commit dfab25c

Browse files
authored
feat: readonly file/image fields (#1591)
1 parent 9c1a2ad commit dfab25c

File tree

3 files changed

+60
-1
lines changed

3 files changed

+60
-1
lines changed

src/unfold/fields.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
from typing import Union
2+
13
from django.contrib.admin import helpers
24
from django.contrib.admin.utils import lookup_field, quote
35
from django.core.exceptions import ObjectDoesNotExist
46
from django.db import models
57
from django.db.models import (
8+
FileField,
69
ForeignObjectRel,
710
ImageField,
811
JSONField,
@@ -36,6 +39,30 @@ def label_tag(self) -> SafeText:
3639

3740
return format_html("<label{}>{}</label>", flatatt(attrs), capfirst(label))
3841

42+
@property
43+
def url(self) -> Union[str, bool]:
44+
field, obj, model_admin = (
45+
self.field["field"],
46+
self.form.instance,
47+
self.model_admin,
48+
)
49+
50+
try:
51+
f, attr, value = lookup_field(field, obj, model_admin)
52+
except (AttributeError, ValueError, ObjectDoesNotExist):
53+
return False
54+
55+
if not self.is_file():
56+
return False
57+
58+
if hasattr(obj, field):
59+
field_value = getattr(obj, field)
60+
61+
if field_value and hasattr(field_value, "url"):
62+
return field_value.url
63+
64+
return False
65+
3966
def is_json(self) -> bool:
4067
field, obj, model_admin = (
4168
self.field["field"],
@@ -73,6 +100,20 @@ def is_image(self) -> bool:
73100

74101
return isinstance(f, ImageField)
75102

103+
def is_file(self) -> bool:
104+
field, obj, model_admin = (
105+
self.field["field"],
106+
self.form.instance,
107+
self.model_admin,
108+
)
109+
110+
try:
111+
f, attr, value = lookup_field(field, obj, model_admin)
112+
except (AttributeError, ValueError, ObjectDoesNotExist):
113+
return False
114+
115+
return isinstance(f, (ImageField, FileField))
116+
76117
def contents(self) -> str:
77118
contents = self._get_contents()
78119
contents = self._preprocess_field(contents)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<div class="readonly break-words {% if field.is_json %}max-w-4xl{% else %}max-w-2xl{% endif %} py-2 text-sm *:rounded-default {% if not adminform.model_admin.compressed_fields and not field.is_image %}bg-base-50 border border-base-200 font-medium px-3 rounded-default shadow-xs dark:border-base-700 dark:bg-base-800{% endif %} {% if field.is_image %}inline-block [&_img]:rounded-default py-0!{% endif %}">{% if value %}{{ value }}{% elif field.contents %}{{ field.contents }}{% else %}-{% endif %}</div>
1+
<div class="readonly break-words {% if field.is_json %}max-w-4xl{% else %}max-w-2xl{% endif %} py-2 text-sm *:rounded-default {% if not adminform.model_admin.compressed_fields and not field.is_image %}bg-base-50 border border-base-200 font-medium px-3 rounded-default shadow-xs dark:border-base-700 dark:bg-base-800{% endif %}">{% if value %}{{ value }}{% elif field.contents %}{% if field.is_file %}{% include "unfold/helpers/field_readonly_value_file.html" %}{% else %}{{ field.contents }}{% endif %}{% else %}-{% endif %}</div>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{% load i18n %}
2+
3+
{% with url=field.url %}
4+
{% if not url %}
5+
<span class="flex items-center">-<span>
6+
{% elif field.is_image %}
7+
<a href="{{ url }}" target="_blank" class="block max-w-48">
8+
<img src="{{ url }}" alt="{% trans 'Image preview' %}" class="block rounded-default" />
9+
</a>
10+
{% else %}
11+
<a href="{{ url }}" target="_blank">
12+
<span class="flex items-center gap-2">
13+
<span class="text-primary-600 dark:text-primary-500">{% trans "Click to download" %}</span>
14+
<span class="material-symbols-outlined text-base-400 dark:text-base-500">download</span>
15+
</span>
16+
</a>
17+
{% endif %}
18+
{% endwith %}

0 commit comments

Comments
 (0)