Search code examples
djangodjango-adminfilefield

Is it possible to change the status of filefield in admin - DJANGO


I'm new with django and I was wondering if it is possible to change the status Currently(see the pic) of a filefield to other things like maybe: all, list... Because currently only return the last uploaded item. I have uploaded 5 file(File1, FIle2, .., File5) on a specific field, base on user ID, but it only return file5. I want to display all uploaded files and be able to get it via template.

See picture

I am able to see the complete list after the insertion in the db, via command prompt but only the last uploaded file is display in django admin.

My models.py :

class Student(models.Model):
    name = models.CharField(max_length=400, null=True, blank=True)
    codePerm = models.CharField(max_length=200, null=True)
    files = models.FileField(blank=True, null=True)

admin.py :

@admin.register(Student)
class userdat(ImportExportModelAdmin):
        list_display = ('name', 'codePerm', 'files')            
        pass

My project consists in processing data from an excel file. There are more than 10 000 elements in the excel file.

I can import the excel file into the sqlite DB and i can browse the data. However each student has files (5 files) associated with them that are saved locally in a folder that I need to add to the DB. I am looking for a way to import all 5 files per student in one go to save time instead of importing the files one by one for each student since I have over 10,000 students it would take me longer.

Is there a way to import the files grouped by student or what would be the best way to process the data? Thank you in advance for your help


Solution

  • With models.FileField in your Student model you can add only one file for each student. Every new upload replaces the old file. That is why in the admin you only see the file that is currently in the database. If you want to add more than one file for each student, you need to use ForeignKey and Inline. Here is an example (you need to adjust it to work with your ImportExportModelAdmin class):

    models.py

    class Student(models.Model):
        name = models.CharField(max_length=400, null=True, blank=True)
        codePerm = models.CharField(max_length=200, null=True)
    
    class StudentFiles(models.Model):
        student = models.ForeignKey('Student',
            on_delete=models.CASCADE,
            related_name='files'
        )
        file = models.FileField()
    

    admin.py

    from .models import Student, StudentFiles
    
    class StudentFilesInline(admin.TabularInline):
        model = StudentFiles
    
    @admin.register(Student)
    class StudentAdmin(admin.ModelAdmin):           
            inlines = [StudentFilesInline,]
    

    Now if you want to upload multiple files at once, you are going to need a custom form field for this. I find this tutorial helpful. For example, you can create forms.py in your app and add this code:

    forms.py

    from django import forms
    from .models import Student, StudentFiles
    
    class StudentAdminForm(forms.ModelForm):
        class Meta:
            model = Student
            # Display all default fields without change
            fields = '__all__'
        
        # Create a new field with 'multiple' attribute
        files = forms.FileField(
            widget=forms.ClearableFileInput(attrs={'multiple': True}),
            label='Upload multiple files at once',
            required=False,
        )
    
        def save_files(self, student):
            # Save each file in the StudentFiles model
            for upload in self.files.getlist('files'):
                file = StudentFiles(student=student, file=upload)
                file.save()
    

    And then adjust the admin.py accordingly:

    from django.contrib import admin
    from .models import Student, StudentFiles
    from .forms import StudentAdminForm
    
    class StudentFilesInline(admin.TabularInline):
        model = StudentFiles
    
    @admin.register(Student)
    class StudentAdmin(admin.ModelAdmin):         
        inlines = [StudentFilesInline,]
        form = StudentAdminForm
    
        def save_related(self, request, form, formsets, change):
            super().save_related(request, form, formsets, change)
            form.save_files(form.instance)
    

    With all of this you will be able to upload many files at once and later replace/delete any of them.

    EDIT: There is a simpler way explained in this Quora post. You can get rid of the save_files() and save_related(). Use save_model() instead:

    forms.py

    from django import forms
    from .models import Student
    
    class StudentAdminForm(forms.ModelForm):
        class Meta:
            model = Student
            # Display all default fields without change
            fields = '__all__'
    
        # Create a new field with 'multiple' attribute
        files = forms.FileField(
            widget=forms.ClearableFileInput(attrs={'multiple': True}),
            label='Upload multiple files at once',
            required=False,
        )
    

    admin.py

    from django.contrib import admin
    from .models import Student, StudentFiles
    from .forms import StudentAdminForm
    
    class StudentFilesInline(admin.TabularInline):
        model = StudentFiles
    
    @admin.register(Student)
    class StudentAdmin(admin.ModelAdmin):         
        inlines = [StudentFilesInline,]
        form = StudentAdminForm
    
        def save_model(self, request, obj, form, change): 
            obj.save() 
     
            for file in request.FILES.getlist('files'): 
                obj.files.create(file=file)