Opened 9 years ago

Last modified 2 years ago

#25756 new Bug

ArrayField does not work with FileField

Reported by: Anthony Dong Owned by:
Component: contrib.postgres Version: 2.2
Severity: Normal Keywords:
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

When using the following models.py definition :

from django.contrib.postgres.fields import ArrayField

class Album(models.Model):
    pictures = ArrayField(models.FileField(upload_to='files'))

And the following admin.py

from django.contrib.postgres.forms import SplitArrayField
class AlbumForm(forms.ModelForm):
    pictures = SplitArrayField(forms.FileField(), size=2)
    class Meta:
        model = models.Album
        fields = '__all__'

class AlbumAdmin(admin.ModelAdmin):
    form = AlbumForm

admin.site.register(models.Album, AlbumAdmin)

Creating a new Album in the Django admin works, but:

  • Files are not getting saved
  • Retrieving a FieldFile is impossible:
    python manage.py shell
    from my_app.models import Album
    Album.objects.get().pictures == [u'filename.png', u'filename2.png']
    

I would have expected a list of FieldFiles.

Attachments (1)

multiple.py (4.5 KB ) - added by Riccardo Di Virgilio 9 years ago.

Download all attachments as: .zip

Change History (12)

comment:1 by Tim Graham, 9 years ago

Triage Stage: UnreviewedAccepted

I'm not sure to what extent we can fix this, but if not, we can document the limitation or try to add a helpful error message indicating that it's unsupported.

comment:2 by Riccardo Di Virgilio, 9 years ago

Hi, I need to implement an array field for multiple files, and currently this is not supported.

https://code.djangoproject.com/ticket/25756

after hours of debugging I found out several design problems that are preventing to have a clean implementation of this field.

  1. If you use a FileField this field is using a descriptor to transform strings into File objects (instead of to_python), which is why the array field is always returning strings and not file objects.
  1. The save method of FileField is setting the instance file attribute to a file, which in this case is wrong because it should be a list of files.
  1. the pre save method in file field is the one that is actually saving the file, since ArrayField is not calling the super of that, this cannot work.

array field should support file field out of the box (and this involves also creating a multi file input widget that can work also in the admin).

another solution is to have a special ArrayFileField, which can also return an ArrayFile object that is iterable (instead of a list).

I can attach a "working" and dirty version of it.

Version 4, edited 9 years ago by Riccardo Di Virgilio (previous) (next) (diff)

by Riccardo Di Virgilio, 9 years ago

Attachment: multiple.py added

comment:3 by Nikolai Ryzhkov, 8 years ago

Hi. I've faced this limitation.

After quick review of FileField and ArrayField I found out that this problem can't be resolved without redesign of ArrayField.
We can't append a FileField's instance to list which is a instance of ArrayField. The FileField's instance requires access to field (It should get upload_to and storage). So we should have wrapper under list which will be know his field first.

comment:4 by Jack, 7 years ago

How is this situation in 1.11? Is it still not working?

comment:5 by Alex, 7 years ago

Replying to Jack:

How is this situation in 1.11? Is it still not working?

I tried to replicate this bug last night; I followed the original posted instructions in this ticket.

It appears to still be a valid bug, although difficult to say for sure without a thorough test.

Tested relevant software versions:
Django version 2.0
Python version 3.6
Postgresql version 10.3

Steps followed to reproduce as described in this ticket.

Results observed consistent with those described in this ticket:

Files are not getting saved in any observable place
Retrieving a FileField is impossible:

(same as previously reported)

    python manage.py shell
    >>> from my_app.models import Album
    >>> Album.objects.get().pictures == [u'filename.png', u'filename2.png']
    >>> true

Album object appears to incorrectly contain filename strings rather than expected <FieldFile: files/filename.png> FieldFile type data.

Last edited 7 years ago by Alex (previous) (diff)

comment:6 by johnthagen, 5 years ago

Bug still exists in 2.2.10. This transitively affects users of Django REST Framework who try to serialize multiple Base64 files into a ListField:

# models.py
from django.contrib.postgres.fields import ArrayField

class Store(Model):
    files = ArrayField(models.FileField(upload_to='files', null=True, blank=True))
# serializers.py
from drf_extra_fields.fields import Base64ImageField
from rest_framework.fields import ListField

class StoreSerializer(ModelSerializer):
    datasheets = ListField(child=Base64ImageField())

    class Meta:
        model = Store
        fields = '__all__'
# views.py
class StoreViewSet(ModelViewSet):
    queryset = Store.objects.all()
    serializer_class = StoreSerializer

Doing this results in incorrect results, returning null instead of a file path and failing to save the file. Would be really nice if it was possible to fix this.

in reply to:  6 comment:7 by Mariusz Felisiak, 5 years ago

Version: 1.82.2

Replying to johnthagen:

Doing this results in incorrect results, returning null instead of a file path and failing to save the file. Would be really nice if it was possible to fix this.

Feel-free to prepare a patch.

comment:8 by Laszlo Marai, 4 years ago

I've just ran into this (after trying to fix a 3rd party ArrayList field+widget for the admin site). What I've found, after hours of debugging is basically identical to Ricardo's comment from 5 years ago. I understand that this is a larger change and probably not too many people are affected anyway, but could someone please update the documentation to save time for anyone who may have the idea of using ArrayListField with a FileField?

Currently, it says (under the base_field section):

Most field types are permitted, with the exception of those handling relational data (ForeignKey, OneToOneField and ManyToManyField).

This (the exceptions) should be extended with ArrayField. Though, it would probably be better to list the ones that are known to work with it.

Last edited 4 years ago by Laszlo Marai (previous) (diff)

comment:9 by Claude Paroz, 2 years ago

PR to document the limitation.

comment:10 by GitHub <noreply@…>, 2 years ago

In a46dfa87:

Refs #25756 -- Doc'd inability to use file fields with PostgreSQL ArrayField.

comment:11 by Mariusz Felisiak <felisiak.mariusz@…>, 2 years ago

In 1fd79033:

[4.1.x] Refs #25756 -- Doc'd inability to use file fields with PostgreSQL ArrayField.

Backport of a46dfa87d0ba690125be98f7f1b77062a1794fdc from main

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