2

I'm using SeparatedValuesField to keep track of a list of strings as explained by http://davidcramer.posterous.com/code/181/custom-fields-in-django.html and many posts here on SO that recommend this as the right way to store a list of strings.

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    device_ids = SeparatedValuesField(blank=True, null=True, default=[])

It is working fine in my application, I can add device ids and view them in the admin interface as expected.

user_profile.device_ids = ['666666-D849-524F-6984-7E9B2D768546']

But the problem is in the admin interface, when I open up the detail page for a UserProfile object, the admin interface itself is adding extra values to my device_ids field.

For example, my application inserts a value into the field, and when I view it in the admin interface it looks like this:

[u'666666-D849-524F-6984-7E9B2D768546']

Then I change some other random property on my UserProfile object and save it using the built in django admin interface save button.

When I open the UserProfile object detail page up again for my object, that value now looks like this:

[u"[u'666666-D849-524F-6984-7E9B2D768546']"]

If I repeat this process of just hitting save then opening up this detail page, it will continue nesting the actual value with u"[ ] characters.

Is there something I can do to change this functionality? Should I be storing the list of strings in a different way?

supervacuo
  • 9,072
  • 2
  • 44
  • 61
b-ryce
  • 5,752
  • 7
  • 49
  • 79

2 Answers2

1

I had the same exact problem, and finally figured it out thanks to these two different answers.

What you need in this situation is a custom widget that renders the list of strings as a string. This widget needs to be tied to the custom field:

class FlattenListWidget(forms.TextInput):
    def render(self, name, value, attrs=None):
        if not value is None:
            value = ','.join(str(v) for v in value)
        return super(FlattenListWidget, self).render(name, value, attrs)

class UserProfileAdminForm(forms.ModelForm):
    class Meta:
        model = UserModel
        widgets = {
            'device_ids': FlattenListWidget(),
        }

class UserProfileAdmin(admin.ModelAdmin):
    form = UserProfileAdminForm

Hope that works. I had different model names in my code but managed to get a text input containing a comma separated list of values from my custom field.

If you want to join the strings with a comma and a space value = ', '.join(str(v) for v in value), remember to strip() the value in the custom field's get_db_prep_value method. Otherwise the spaces will be saved back to database.

To use the custom field in list_display you can add a custom field to the admin model:

class UserProfileAdmin(admin.ModelAdmin):
    form = UserProfileAdminForm

    list_display = ('ids_list',)
    def ids_list(self, obj):
        if obj.device_ids:
            return ', '.join(str(i) for i in obj.device_ids)
        return None
Community
  • 1
  • 1
Oiva Eskola
  • 949
  • 8
  • 13
1

Oiva Eskola's answer looks fine (haven't tried it, though).

Finding the Django source before this question, I also stumbled upon the following (which works):

SeparatedValuesField(models.TextField):
    # ...

    def value_from_object(self, obj):
        return self.get_db_prep_value(super(SeparatedValuesField, self).value_from_object(obj))
supervacuo
  • 9,072
  • 2
  • 44
  • 61