I'm using an Ajax code for uploading files. Django takes good care of file uploads on ModelForms. Just writing form.save() would upload any file data in the header, manage creating the folders if needed and even rename the file if a duplicate already exists. Take this ModelForm which only has one filed named file for example:
class UploadFileForm(ModelForm):
class Meta:
model = MyModel
fields = ('file',)
Since I'm using Ajax the only information I have in my view is request.FILES['file']. This is what I tried in my view:
form = UploadFileForm(initial={'file':request.FILES['file']})
if form.is_valid():
form.save()
But it returns an invalid form (file is required). I can do this using pure Python but with the power of Django where's the point in that?
form = UploadFileForm(request.FILES)
if form.is_valid():
form.save()
initial parameter let you initialize form fields, like giving a new form filed some initial data.
Here, you are getting the file data from a request.
Related
Why we use cleaned_data firstname= form.cleaned_data.get("first_name")
What is the point in this and why is it necessary?
When you call is_valid() method on a form, it results in validation and cleaning of the form data. In the process, Django creates an attribute called cleaned_data , a dictionary which contains cleaned data only from the fields which have passed the validation tests.
There 2 are two types: basic Form (forms.Form) and ModelForm (forms.ModelForm).
If you are using a ModelForm then there is no any need of using a cleaned_data dictionary because when you do form.save() it's already be matched and the clean data is saved. But you are using basic Form then you have to manually match each cleaned_data to its database place and then save the instance to the database not the form.
For example basic Form:
if form.is_valid():
ex = Example()
ex.username = form.cleaned_data['username']
ex.save()
For example ModelForm:
if form.is_valid():
form.save()
IMPORTANT: If the form pass from is_valid() stage then there is no any unvalidated data.
When data has been submitted to the database through the forms, it has to be validated or the user has to be authenticated.
When it's being returned to the user this is how it's being accessed
name = form.cleaned_data['name']
here I've used just a name but one can also use an email
When the data is returned it's returned in a more readable format.
I am new to Django and would like to seek advise regarding file uploads. The user can upload multiple files, but I do not wish to store the files in the database. I just want to get the data from the files and store the data in the database. Is there a way to do it? Is storing the files locally the way to do it?
I have seen ways to temporarily store the files locally (but I have seen examples where we need to specify our own (computer) path which may be different for different computers). Is there a way to specify a path where any computers can store the files locally?
Apologies that there is no code as I am still thinking how am I going to do it.
Most people would say just store the file paths in the database and have the web server serve the files. Unless you want people to upload something like a spreadsheet, then you should use a spreadsheet plugin to get the contents into lists and dictionaries which you can write out as models.
Heres how to do it the way you requested:
def handle_uploaded_file(upload):
contents = file.read() # Add .decode('ascii') if Python 3
my_model = MyModel(some_other_field='something')
my_model.field = contents
my_model.save()
class UploadFileForm(forms.Form):
title = forms.CharField(max_length=50)
file = forms.FileField()
def upload_file(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
handle_uploaded_file(request.FILES['file'])
return HttpResponseRedirect('/success/url/')
else:
form = UploadFileForm()
return render(request, 'upload.html', {'form': form})
I have models like this:
User:
#somefields
apps = models.ManyToManyField(App)
Here, User is created initially during registration. He links apps using many to many in a separate page where user selects(multiple) only apps, no other fields.
What is the best way to populate apps in Django ?
For example, if we can create User also, we can simply use modelform where .save(commit=False) will create user and .save_m2m() will link apps. But here we dont need to create User. We will be having user already, we only need to add apps. How ?
Newly added details:
I know how to do with normal "form" and normal web way. But I want to write quality code so want to know. If there is nothing wrong in using normal form then its fine.
There are multiple ways to do it, but for example:
class UserAppForm(ModelForm):
class Meta:
model = User
fields = ['apps']
And in your view, you configure the routing so that you can:
Get the ID of the user to select
Raise an error if you do not find the ID (Instead of creating a new one)
Initialize the form with the user
For example:
def user_add_app(request, pk):
user = get_object_or_404(User, pk=pk)
if request.method == "POST":
form = UserAppForm(request.POST, instance=user)
if form.is_valid():
user = form.save()
return HttpResponseRedirect(<some redirect>)
else:
form = EmployeeForm(instance=user)
return render(request, "<some html file>", {'form': form})
Maybe I did not fully understand the question (Please clarify if it's not the case), but there is no problem having two forms on the same model:
One form to create the User, without selecting apps (Which will be empty)
One form to add Apps to the User, taking into account that it already exists (And is not created at this time).
Does it answer the question ?
You can create a ModelForm form with model = App and a User field. Now when creating the form set an initial value for User :
form = AppForm(initial={'user': 1})
I have created a ModelForm with fields, title, file and content. Here file is a FileField(). But I can't call the save() method of this form due to some reasons. So I have to maually created one Model Object and assign cleaned values to that object. Everything worked excpt that FileField. The file is not saving. How can I fix this? Is it the correct method to extract FileField?
Form
class TestForm(forms.ModelForm):
class Meta:
model = Test
fields = ('title','file', 'content',)
Views.py
form = TestForm(request.POST,request.FILES)
if form.is_valid():
content = form.cleaned_data['content']
file = form.cleaned_data['file']
title = form.cleaned_data['title']
fax = Fax()
fax.title = title
fax.file = file
fax.content = content
fax.save()
Here the file is not saving. How can I fix this?
Any help will be appreciated!
Have u used enctype="multipart/form-data" in your form
Seems like the code is fine.
Please using this type of validation. This may work
if request.method == 'POST':
form = ModelFormWithFileField(request.POST, request.FILES)
if form.is_valid():
# file is saved
form.save()
return HttpResponseRedirect('/success/url/')``
I think you can use
request.FILES['file']
for getting the file object
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?
You can create two forms:
A form based on django.forms.Form which is used to get the file from request
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
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
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
To achieve this you have to write some custom code. Each FileField has a connected File object. You can read the content of this file object like you would when dealing with files in Python.
There are of course different locations you could do that. You can overwrite the forms/models save method which contains the FileField. If you have model you could use pre_save/post_save signals as well.