Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django: Upload a file and read its content to populate a model?

I am new to Django and would like to know what is the Django-way to add elements in a database not by entering each field from an html form (like it is done by default) but uploading a single file (for example a json file) that will be used to populate the database?

So let say the model has only three fields: title,description,quantity. And I have a text file (myFile.txt) with "myTitle:myDesc" written in it.

What I want is just a FileField that will accept a text file so I can upload myFile.txt and the title and description will be read from this file. And at the same time the quantity will be asked "normally" in a text input as it would be by default (only title and description are read from the file).

Of course, validation on the file will be done to accept/deny the uploaded file. The problem I am facing is that if I add a FileField to the model, the file will be stored in the local storage. I want the content of the uploaded file to be read, used to create an entry in the model, and then deleted.

Even the admin should not be able to manually add an element entering the title and description in a HTML form but only by uploading a file. Can someone help me in a Django-way?

like image 610
Thomas Avatar asked May 23 '11 01:05

Thomas


3 Answers

You can create two forms:

  1. A form based on django.forms.Form which is used to get the file from request
  2. A model form which is used to validate model fields and create a model object

Then you can call the second form from the first one, like this:

class MyModelForm(ModelForm):

    class Meta:
        model = MyModel


class FileUploadForm(forms.Form):

    file = forms.FileField()

    def clean_file(self):
        data = self.cleaned_data["file"]
        # read and parse the file, create a Python dictionary `data_dict` from it
        form = MyModelForm(data_dict)
        if form.is_valid():
            # we don't want to put the object to the database on this step
            self.instance = form.save(commit=False) 
        else:
            # You can use more specific error message here
            raise forms.ValidationError(u"The file contains invalid data.")
        return data

    def save(self):
        # We are not overriding the `save` method here because `form.Form` does not have it. 
        # We just add it for convenience.
        instance = getattr(self, "instance", None)
        if instance:
            instance.save()
        return instance

def my_view(request):
    form = FileUploadForm(request.POST, request.FILES)
    if form.is_valid():
        form.save()
    else:
        # display errors
like image 132
Andrey Fedoseev Avatar answered Nov 15 '22 04:11

Andrey Fedoseev


You can use form wizard to achieve such tasks. The basic idea is to create two forms; one with the FileField and the other form with the title, description quantity fields.

The user views the form with FileField first. Once the user uploads the file and submits the request, you can render the other form with initial values read from the file (you can also delete the file at this step).

Regarding the admin functionality, you can read about how to integrate form wizard with admin here

like image 2
Konstant Avatar answered Nov 15 '22 04:11

Konstant


I found another way of populating a model before saving it.

Instead of using pre_save, or using 2 different forms, if we are using the admin.ModelAdmin, we can simply redefine the save_model() method:

def save_model(self, request, obj, form, change):
  obj.user = request.user
  # populate the model
  obj.save()
  # post actions if needed
like image 1
Thomas Avatar answered Nov 15 '22 03:11

Thomas