Opened 3 months ago

Closed 3 months ago

#35536 closed Cleanup/optimization (wontfix)

Incorrect represent empty list from JSONField in ChangeList

Reported by: Denis Dudnik Owned by: nobody
Component: contrib.admin Version: 5.0
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: yes UI/UX: no

Description

I have a model like this:

class HistoryEvent(models.Model):
    name = models.TextField()
    value = JSONField(blank=True, null=True)
    edit_at = models.DateTimeField(default=timezone.now)
    edit_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

I have a number of records with values like these:

  1. Empty list - []
  2. Empty dict - {}

I have registered ModelAdmin like this:

@admin.register(HistoryEvent)
class HistoryEventAdmin(admin.ModelAdmin):
    list_display = ("name", "value")

When I open a page with data in the admin panel, I find some things:

  1. Empty dict represents as a text like this"{}"
  2. Empty list represents as an empty text like this"" while I wait "[]"

The problem could be here:
django 5.0.6
file: django/contrib/admin/utils.py

def display_for_field(value, field, empty_value_display):
    from django.contrib.admin.templatetags.admin_list import _boolean_icon

    if getattr(field, "flatchoices", None):
        try:
            return dict(field.flatchoices).get(value, empty_value_display)
        except TypeError:
            # Allow list-like choices.
            flatchoices = make_hashable(field.flatchoices)
            value = make_hashable(value)
            return dict(flatchoices).get(value, empty_value_display)

    # BooleanField needs special-case null-handling, so it comes before the
    # general null test.
    elif isinstance(field, models.BooleanField):
        return _boolean_icon(value)
    elif value is None:
        return empty_value_display
    elif isinstance(field, models.DateTimeField):
        return formats.localize(timezone.template_localtime(value))
    elif isinstance(field, (models.DateField, models.TimeField)):
        return formats.localize(value)
    elif isinstance(field, models.DecimalField):
        return formats.number_format(value, field.decimal_places)
    elif isinstance(field, (models.IntegerField, models.FloatField)):
        return formats.number_format(value)
    elif isinstance(field, models.FileField) and value:
        return format_html('<a href="{}">{}</a>', value.url, value)
    elif isinstance(field, models.JSONField) and value:
        try:
            return json.dumps(value, ensure_ascii=False, cls=field.encoder)
        except TypeError:
            return display_for_value(value, empty_value_display)
    else:
        return display_for_value(value, empty_value_display)

I think this line:

elif isinstance(field, models.JSONField) and value:

should be like this:

elif isinstance(field, models.JSONField):

because of empty list could be dumps and shouldn't be joined.
Join for empty list return empty string, and this looks confusion.

Before (Now)

NAME     VALUE
TEST              

After

NAME     VALUE
TEST     []

Change History (1)

comment:1 by Sarah Boyce, 3 months ago

Resolution: wontfix
Status: newclosed

I believe this is happening because JSONField uses the default set of empty_values which include {} and []
Since this ticket #19997, you can customise the empty values of forms fields and, due to the test written in 4cccb85e292fea01b3459cd97d751ed35179a7b7, I think this looks intentional.
I think we need some more opinions before we would make a change here.
If you think the default for JSONField should be updated, perhaps you can propose this on the forum and see if other people agree with you?

Note: See TracTickets for help on using tickets.
Back to Top