Django Admin Model ArrayField Change Delimiter

2019-08-24 14:50发布

问题:

My model looks like this:

from django.contrib.postgres.fields import ArrayField
class Trigger(models.Model):
    solutions = ArrayField(models.TextField(blank=True, null=True), blank=True, null=True, help_text='some helpful text')

This allows me to enter a list of solutions separated by a comma by default. For example: I can enter in that textfield:

1. watch out for dust.,
2. keep away from furry animals.,

This does create a list of two separate string items. However, if a solution text itself contains a comma, for example:

1. cockroaches, polens and molds might be harmful. 

This will create two separate solution lines, because of the existence of a comma in that sentence.

How do I tell django to use a different delimiter than comma as it would be almost certainly a part of sentences. How can I use a separator like '|'? I looked inside the arrayfield class, but it doesn't allow any separator.

回答1:

Some relevant documentation:

  • https://docs.djangoproject.com/en/1.11/ref/contrib/postgres/fields/#arrayfield
  • https://docs.djangoproject.com/en/1.11/ref/contrib/postgres/forms/#simplearrayfield

If you're using built in forms on the admin site, or using a ModelForm without customising any fields then the field is probably automatically using the SimpleArrayField form field. It looks like you can override the delimiter character. The documentation states this caveat:

The field does not support escaping of the delimiter, so be careful in cases where the delimiter is a valid character in the underlying field. The delimiter does not need to be only one character.


Anyways, you could do this by providing a custom form like this...

# forms.py

from django import forms
from .models import Trigger


class TriggerForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['solutions'].delimiter = '|'  # Or whichever other character you want.

    class Meta:
        model = Trigger
        fields = '__all__'

And if this is for use in the admin site...

# admin.py

from django.contrib import admin
from .forms import TriggerForm
from .models import Trigger


@admin.register(Trigger)
class TriggerAdmin(admin.ModelAdmin):
    form = TriggerForm


回答2:

Slightly cleaner solution (without overriding the __init__ in the Form class) would be to just specify the field on the form.

from django.contrib.postgres.forms import SimpleArrayField
from django import forms
from django.forms.fields import CharField
from django.forms.widgets import Textarea

class TriggerForm(forms.ModelForm):
    solutions = SimpleArrayField(CharField(), delimiter='|', widget=Textarea())

This way you can easily choose to go with, for example SplitArrayField or specify different widget for the field.