Add a new Django field, IETFJSONField
This field is needed because the plain JSONField does not permit empty arrays - [] - or empty objects - {} - when the field is marked as required. Those values explicitly evaluate to a null value, and are rejected. Instead, the IETFJSONField accepts two new arguments to control this: - empty_values: An array of values that should evaluate to null/empty, and be rejected. - accepted_empty_values: An array of values that should *not* evaluate to null/empty, and be accepted. This allows the programmer to specify either a positive or negative statement of what values to accept. Fixes issue #3331. Commit ready for merge. - Legacy-Id: 19401
This commit is contained in:
parent
58fa3218eb
commit
604d6edef0
|
@ -23,6 +23,7 @@ import debug # pyflakes:ignore
|
|||
from ietf.group.colors import fg_group_colors, bg_group_colors
|
||||
from ietf.name.models import GroupStateName, GroupTypeName, DocTagName, GroupMilestoneStateName, RoleName, AgendaTypeName, ExtResourceName
|
||||
from ietf.person.models import Email, Person
|
||||
from ietf.utils.db import IETFJSONField
|
||||
from ietf.utils.mail import formataddr, send_mail_text
|
||||
from ietf.utils import log
|
||||
from ietf.utils.models import ForeignKey, OneToOneField
|
||||
|
@ -282,14 +283,14 @@ class GroupFeatures(models.Model):
|
|||
agenda_type = models.ForeignKey(AgendaTypeName, null=True, default="ietf", on_delete=CASCADE)
|
||||
about_page = models.CharField(max_length=64, blank=False, default="ietf.group.views.group_about" )
|
||||
default_tab = models.CharField(max_length=64, blank=False, default="ietf.group.views.group_about" )
|
||||
material_types = jsonfield.JSONField(max_length=64, blank=False, default=["slides"])
|
||||
default_used_roles = jsonfield.JSONField(max_length=256, blank=False, default=[])
|
||||
admin_roles = jsonfield.JSONField(max_length=64, blank=False, default=["chair"]) # Trac Admin
|
||||
docman_roles = jsonfield.JSONField(max_length=128, blank=False, default=["ad","chair","delegate","secr"])
|
||||
groupman_roles = jsonfield.JSONField(max_length=128, blank=False, default=["ad","chair",])
|
||||
groupman_authroles = jsonfield.JSONField(max_length=128, blank=False, default=["Secretariat",])
|
||||
matman_roles = jsonfield.JSONField(max_length=128, blank=False, default=["ad","chair","delegate","secr"])
|
||||
role_order = jsonfield.JSONField(max_length=128, blank=False, default=["chair","secr","member"],
|
||||
material_types = IETFJSONField(max_length=64, accepted_empty_values=[[], {}], blank=False, default=["slides"])
|
||||
default_used_roles = IETFJSONField(max_length=256, accepted_empty_values=[[], {}], blank=False, default=[])
|
||||
admin_roles = IETFJSONField(max_length=64, accepted_empty_values=[[], {}], blank=False, default=["chair"]) # Trac Admin
|
||||
docman_roles = IETFJSONField(max_length=128, accepted_empty_values=[[], {}], blank=False, default=["ad","chair","delegate","secr"])
|
||||
groupman_roles = IETFJSONField(max_length=128, accepted_empty_values=[[], {}], blank=False, default=["ad","chair",])
|
||||
groupman_authroles = IETFJSONField(max_length=128, accepted_empty_values=[[], {}], blank=False, default=["Secretariat",])
|
||||
matman_roles = IETFJSONField(max_length=128, accepted_empty_values=[[], {}], blank=False, default=["ad","chair","delegate","secr"])
|
||||
role_order = IETFJSONField(max_length=128, accepted_empty_values=[[], {}], blank=False, default=["chair","secr","member"],
|
||||
help_text="The order in which roles are shown, for instance on photo pages. Enter valid JSON.")
|
||||
|
||||
|
||||
|
|
28
ietf/utils/db.py
Normal file
28
ietf/utils/db.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
# Copyright The IETF Trust 2021, All Rights Reserved
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Taken from/inspired by
|
||||
# https://stackoverflow.com/questions/55147169/django-admin-jsonfield-default-empty-dict-wont-save-in-admin
|
||||
#
|
||||
# JSONField should recognize {}, (), and [] as valid, non-empty JSON
|
||||
# values. However, the base Field class excludes them
|
||||
import jsonfield
|
||||
|
||||
from ietf.utils.fields import IETFJSONField as FormIETFJSONField
|
||||
|
||||
|
||||
class IETFJSONField(jsonfield.JSONField):
|
||||
form_class = FormIETFJSONField
|
||||
|
||||
def __init__(self, *args, empty_values=FormIETFJSONField.empty_values, accepted_empty_values=None, **kwargs):
|
||||
if accepted_empty_values is None:
|
||||
accepted_empty_values = []
|
||||
self.empty_values = [x
|
||||
for x in empty_values
|
||||
if x not in accepted_empty_values]
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
if issubclass(kwargs['form_class'], FormIETFJSONField):
|
||||
kwargs.setdefault('empty_values', self.empty_values)
|
||||
return super().formfield(**{**kwargs})
|
|
@ -6,6 +6,8 @@ import datetime
|
|||
import json
|
||||
import re
|
||||
|
||||
import jsonfield
|
||||
|
||||
import debug # pyflakes:ignore
|
||||
|
||||
from typing import Optional, Type # pyflakes:ignore
|
||||
|
@ -265,6 +267,19 @@ class SearchableField(forms.CharField):
|
|||
|
||||
return objs.first() if self.max_entries == 1 else objs
|
||||
|
||||
|
||||
class IETFJSONField(jsonfield.fields.forms.JSONField):
|
||||
def __init__(self, *args, empty_values=jsonfield.fields.forms.JSONField.empty_values,
|
||||
accepted_empty_values=None, **kwargs):
|
||||
if accepted_empty_values is None:
|
||||
accepted_empty_values = []
|
||||
self.empty_values = [x
|
||||
for x in empty_values
|
||||
if x not in accepted_empty_values]
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
class MissingOkImageField(models.ImageField):
|
||||
"""Image field that can validate successfully if file goes missing
|
||||
|
||||
|
|
Loading…
Reference in a new issue