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)
Change History (12)
comment:1 by , 9 years ago
Triage Stage: | Unreviewed → Accepted |
---|
comment:2 by , 9 years ago
Hi, I need to implement an array field for multiple files, and currently this is not supported.
after hours of debugging I found out several design problems that are preventing to have a clean implementation of this field.
- 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.
- 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.
- 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.
by , 9 years ago
Attachment: | multiple.py added |
---|
comment:3 by , 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:5 by , 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, following the posted instructions.
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.
follow-up: 7 comment:6 by , 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.
comment:7 by , 5 years ago
Version: | 1.8 → 2.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 , 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.
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.