[1.8.x] Fixed #14497 -- Improved admin widget for "read only" FileFields
Based on patch by Adam J Forster, Paul Collins, and Julien.
Backport of 2be621e44c
from master
This commit is contained in:
parent
16e3910e9c
commit
4957b8a406
|
@ -1,23 +1,22 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from collections import defaultdict
|
|
||||||
import datetime
|
import datetime
|
||||||
import decimal
|
import decimal
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
from django.contrib.auth import get_permission_codename
|
from django.contrib.auth import get_permission_codename
|
||||||
from django.core.exceptions import FieldDoesNotExist
|
from django.core.exceptions import FieldDoesNotExist
|
||||||
|
from django.core.urlresolvers import reverse, NoReverseMatch
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models.constants import LOOKUP_SEP
|
from django.db.models.constants import LOOKUP_SEP
|
||||||
from django.db.models.deletion import Collector
|
from django.db.models.deletion import Collector
|
||||||
from django.forms.forms import pretty_name
|
from django.forms.forms import pretty_name
|
||||||
from django.utils import formats
|
from django.utils import formats, six, timezone
|
||||||
from django.utils.html import format_html
|
|
||||||
from django.utils.text import capfirst
|
|
||||||
from django.utils import timezone
|
|
||||||
from django.utils.encoding import force_str, force_text, smart_text
|
from django.utils.encoding import force_str, force_text, smart_text
|
||||||
from django.utils import six
|
from django.utils.html import conditional_escape, format_html
|
||||||
|
from django.utils.safestring import mark_safe
|
||||||
|
from django.utils.text import capfirst
|
||||||
from django.utils.translation import ungettext
|
from django.utils.translation import ungettext
|
||||||
from django.core.urlresolvers import reverse, NoReverseMatch
|
|
||||||
|
|
||||||
|
|
||||||
def lookup_needs_distinct(opts, lookup_path):
|
def lookup_needs_distinct(opts, lookup_path):
|
||||||
|
@ -389,6 +388,11 @@ def display_for_field(value, field):
|
||||||
return formats.number_format(value, field.decimal_places)
|
return formats.number_format(value, field.decimal_places)
|
||||||
elif isinstance(field, models.FloatField):
|
elif isinstance(field, models.FloatField):
|
||||||
return formats.number_format(value)
|
return formats.number_format(value)
|
||||||
|
elif isinstance(field, models.FileField):
|
||||||
|
return mark_safe('<a href="%s">%s</a>' % (
|
||||||
|
conditional_escape(value.url),
|
||||||
|
conditional_escape(value),
|
||||||
|
))
|
||||||
else:
|
else:
|
||||||
return smart_text(value)
|
return smart_text(value)
|
||||||
|
|
||||||
|
|
|
@ -350,26 +350,55 @@ class AdminURLWidgetTest(DjangoTestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class AdminFileWidgetTest(DjangoTestCase):
|
@override_settings(
|
||||||
def test_render(self):
|
PASSWORD_HASHERS=['django.contrib.auth.hashers.SHA1PasswordHasher'],
|
||||||
|
ROOT_URLCONF='admin_widgets.urls',
|
||||||
|
)
|
||||||
|
class AdminFileWidgetTests(DjangoTestCase):
|
||||||
|
fixtures = ['admin-widgets-users.xml']
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
band = models.Band.objects.create(name='Linkin Park')
|
band = models.Band.objects.create(name='Linkin Park')
|
||||||
album = band.album_set.create(
|
self.album = band.album_set.create(
|
||||||
name='Hybrid Theory', cover_art=r'albums\hybrid_theory.jpg'
|
name='Hybrid Theory', cover_art=r'albums\hybrid_theory.jpg'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_render(self):
|
||||||
w = widgets.AdminFileWidget()
|
w = widgets.AdminFileWidget()
|
||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
w.render('test', album.cover_art),
|
w.render('test', self.album.cover_art),
|
||||||
'<p class="file-upload">Currently: <a href="%(STORAGE_URL)salbums/hybrid_theory.jpg">albums\hybrid_theory.jpg</a> <span class="clearable-file-input"><input type="checkbox" name="test-clear" id="test-clear_id" /> <label for="test-clear_id">Clear</label></span><br />Change: <input type="file" name="test" /></p>' % {
|
'<p class="file-upload">Currently: <a href="%(STORAGE_URL)salbums/'
|
||||||
'STORAGE_URL': default_storage.url('')
|
'hybrid_theory.jpg">albums\hybrid_theory.jpg</a> '
|
||||||
|
'<span class="clearable-file-input">'
|
||||||
|
'<input type="checkbox" name="test-clear" id="test-clear_id" /> '
|
||||||
|
'<label for="test-clear_id">Clear</label></span><br />'
|
||||||
|
'Change: <input type="file" name="test" /></p>' % {
|
||||||
|
'STORAGE_URL': default_storage.url(''),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertHTMLEqual(
|
self.assertHTMLEqual(
|
||||||
w.render('test', SimpleUploadedFile('test', b'content')),
|
w.render('test', SimpleUploadedFile('test', b'content')),
|
||||||
'<input type="file" name="test" />',
|
'<input type="file" name="test" />',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_readonly_fields(self):
|
||||||
|
"""
|
||||||
|
File widgets should render as a link when they're marked "read only."
|
||||||
|
"""
|
||||||
|
self.client.login(username="super", password="secret")
|
||||||
|
response = self.client.get('/admin_widgets/album/%s/' % self.album.id)
|
||||||
|
self.assertContains(
|
||||||
|
response,
|
||||||
|
'<p><a href="%(STORAGE_URL)salbums/hybrid_theory.jpg">'
|
||||||
|
'albums\hybrid_theory.jpg</a></p>' % {'STORAGE_URL': default_storage.url('')},
|
||||||
|
html=True,
|
||||||
|
)
|
||||||
|
self.assertNotContains(
|
||||||
|
response,
|
||||||
|
'<input type="file" name="cover_art" id="id_cover_art" />',
|
||||||
|
html=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@override_settings(ROOT_URLCONF='admin_widgets.urls')
|
@override_settings(ROOT_URLCONF='admin_widgets.urls')
|
||||||
class ForeignKeyRawIdWidgetTest(DjangoTestCase):
|
class ForeignKeyRawIdWidgetTest(DjangoTestCase):
|
||||||
|
|
|
@ -24,6 +24,11 @@ class EventAdmin(admin.ModelAdmin):
|
||||||
raw_id_fields = ['main_band', 'supporting_bands']
|
raw_id_fields = ['main_band', 'supporting_bands']
|
||||||
|
|
||||||
|
|
||||||
|
class AlbumAdmin(admin.ModelAdmin):
|
||||||
|
fields = ('name', 'cover_art',)
|
||||||
|
readonly_fields = ('cover_art',)
|
||||||
|
|
||||||
|
|
||||||
class SchoolAdmin(admin.ModelAdmin):
|
class SchoolAdmin(admin.ModelAdmin):
|
||||||
filter_vertical = ('students',)
|
filter_vertical = ('students',)
|
||||||
filter_horizontal = ('alumni',)
|
filter_horizontal = ('alumni',)
|
||||||
|
@ -37,7 +42,7 @@ site.register(models.CarTire, CarTireAdmin)
|
||||||
site.register(models.Member)
|
site.register(models.Member)
|
||||||
site.register(models.Band)
|
site.register(models.Band)
|
||||||
site.register(models.Event, EventAdmin)
|
site.register(models.Event, EventAdmin)
|
||||||
site.register(models.Album)
|
site.register(models.Album, AlbumAdmin)
|
||||||
|
|
||||||
site.register(models.Inventory)
|
site.register(models.Inventory)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue