How to extract File Object from Django Form FileField - django

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

Related

Django validate FileField with clean()

I have a Form that includes a FileField and a CharField. Both work as expected.
Neither field is required by itself, but one of them has to be given. So I want to add a validation that fails if both are empty.
in forms.py:
class MyForm(forms.Form):
mytext = forms.CharField(
label = "Enter text",
required=False
)
myfile = forms.FileField(
label = "Or upload file",
required=False
)
def clean(self):
super(MyForm, self).clean()
mytext_value = self.cleaned_data.get("mytext")
myfile_value = self.cleaned_data.get("myfile") # this remains empty, even after selecting a file! :-(
if not mytext_value and not myfile_value:
self.add_error("mytext", "Either text or file must be given!")
return self.cleaned_data
This validation fails even if a file has been uploaded! (It does not fail if the text field has been used.)
If I disable the validation, the form works fine within the app. In views.py, I can get the uploaded file from the request (myfile_value = request.FILES.get("myfile")) and work with it.
But how do I get the content of the file during the clean() call, where I do not have a request, yet?
self.files gives me an empty MultiValueDict, self.data doesn't contain the key myfile at all, and in self.cleaned_data, myfile is None.
How can I check during form validation whether a FileField has been filled?
The problem was not the form, but the associated view:
Wrong forms.py:
if request.method == "POST":
form = MyForm(request.POST)
if form.is_valid():
mytext = request.POST.get("mytext")
myfile = request.FILES.get("myfile")
I didn't pass request.FILES to the form, so no wonder the validation didn't find it. While below this point, I retrieved the file directly from the request and was fine.
Right forms.py:
if request.method == "POST":
form = MyForm(request.POST, request.FILES)
if form.is_valid():
mytext = form.cleaned_data.get("mytext")
myfile = form.cleaned_data.get("myfile")

Add data to ModelForm object before saving

Say I have a form that looks like this:
forms.py
class CreateASomethingForm(ModelForm):
class Meta:
model = Something
fields = ['field2', 'field3', 'field4']
I want the form to have these three fields. However my Somethingclass also has field1. My question is - how do I add data to field1, if I am not using the ModelForm to collect the data. I tried doing something like this, but it isn't working and I am unsure on the proper way to solve this:
views.py
def create_something_view(request):
if (request.method == 'POST'):
# Create an object of the form based on POST data
obj = CreateASomething(request.POST)
# ** Add data into the blank field1 ** (Throwing an error)
obj['field1'] = request.user
# ... validate, save, then redirect
The error I receive is:
TypeError: 'CreateAClassForm' object does not support item assignment
In Django, what is the proper way to assign data to a ModelForm object before saving?
form = CreateASomething(request.POST)
if form.is_valid():
obj = form.save(commit=False)
obj.field1 = request.user
obj.save()
Sometimes, the field might be required which means you can't make it past form.is_valid(). In that case, you can pass a dict object containing all fields to the form.
if request.method == 'POST':
data = {
'fields1': request.user,
'fields2': additional_data,
}
form = CreateASomethingForm(data)
if form.is_valid():
form.commit(save)
There are two ways given by Django official
LINK : https://docs.djangoproject.com/en/3.0/topics/forms/modelforms/
Method 1]
author = Author(title='Mr')
form = PartialAuthorForm(request.POST, instance=author)
form.save()
Method 2]
form = PartialAuthorForm(request.POST)
author = form.save(commit=False)
author.title = 'Mr'
author.save()
Here is a more suitable way to add data especially used during testing:
First convert an existing entry into a dictionary with the model_to_dict function
from django.forms.models import model_to_dict
...
valid_data = model_to_dict(entry)
Then add the new data into this dictionary
valid_data['finish_time'] = '18:44'
This works better than setting the value in the form
update_form.finish_time = '18:44'
Create the form with the valid data and the instance
update_form = UserEntryForm(valid_data, instance=entry)
Do any assertions you require:
self.assertTrue(update_form.is_valid())
entry = update_form.save()
self.assertEqual(
entry.status,
1
)

how to pass initial value of FileField to Formset (in Django)

I am trying to populate a Django formset using data from a POST/FILE request. I am able to populate all the fields except the FileField. It seems that initial cannot be used to pass the request.FILE to the FormSet creator function. My question is how to pass the FILE to FormSet.
The model.py
class ArticleForm(forms.Form):
docfile = forms.FileField()
subject = forms.Charfield(max_length=128)
ArticleFormSet = formset_factory(ArticleForm, extra=2)
the views.py
formset = ArticleFormSet(request.POST, request.FILE)
#do some other work, and then re-display the POST data
data = formset.cleaned_data
formset = ArticleFormSet(initial=data)
return render_to_response('some.html',
{'formset':formset}
)
You can not pass initial data to a file field.
The <input type="file" /> will always be blank when the browser renders it.
To pass request.FILES to a formset, just specify it as the second argument after POST.
http://docs.djangoproject.com/en/dev/topics/forms/formsets/#using-a-formset-in-views-and-templates
FormSet(request.POST, request.FILES)
You can not pass any initial values when you are working with file uploads.

update forms.FileField on django forms

I have a model with a FileField in it:
class DocumentUpload(models.Model):
document_name = models.CharField(max_length=100, blank=True)
document_path = models.FileField(upload_to='uploads')
and a form which uses this model
class DocumentUploadForm(forms.ModelForm):
class Meta:
model = DocumentUpload
When I use the form to create a new upload everything works fine.
if request.method == 'POST':
form = DocumentUploadForm(request.POST, request.FILES)
if form.is_valid():
form.save()
However when I try and update/edit the entry it updates all the fields apart from the document which is uploaded. This just stays the same as the original upload.
d = get_object_or_404(DocumentUpload, pk=id)
if request.method == 'POST':
form = DocumentUploadForm(data=request.POST, files=request.FILES, instance=d)
if form.is_valid():
u = form.save()
How do I get it to change the upload file when editing the instance?
Thanks
Since it was my idea, I'll post it up as an answer (just to stroke my own ego and/or rating)...
Add the following to your form's template:
enctype="multipart/form-data"
feel free to check it off as an answer...
:)
just needed to add:
enctype="multipart/form-data"
to my form. Thanks Brant

Django - how do you turn an InMemoryUploadedFile into an ImageField's FieldFile?

I've been trying help(django.db.models.ImageField) and dir(django.db.models.ImageField), looking for how you might create a ImageField object from an image that is uploaded.
request.FILES has the images as InMemoryUploadedFile, but I'm trying to save a model that contains an ImageField, so how do I turn the InMemoryUploadedFile into the ImageField?
How do you go about finding this type of thing out? I suspect that the two classes have an inheritance relationship, but I'd have to do lots of dir() -ing to find out if I were to look.
You need to save the InMemoryUploadedFile to the ImageField rather than 'turning' it into an ImageField:
image = request.FILES['img']
foo.imagefield.save(image.name, image)
where foo is the model instance, and imagefield is the ImageField.
Alternatively, if you are pulling the image out of a form:
image = form.cleaned_data.get('img')
foo.imagefield.save(image.name, image)
You trying to do it in ModelForm?
This is how i did for file field
class UploadSongForm(forms.ModelForm):
class Meta:
model = Mp3File
def save(self):
content_type = self.cleaned_data['file'].content_type
filename = gen_md5() + ".mp3"
self.cleaned_data['file'] = SimpleUploadedFile(filename, self.cleaned_data['file'].read(), content_type)
return super(UploadSongForm, self).save()
You can take it as example and look in source what InMemoryUploadedFile class needs in initialization parameters.
You could implement a form with a file upload field by using form instances, here is the view:
def form_view(request):
if request.method == 'POST':
form = FooForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return render_to_response('result.html')
return render_to_response('form.html', {
'form': form;
'error_messages': form.errors;
}
form = FooForm()
return render_to_response('form.html', {
'form': form;
}
form.save() saves the uploaded file along with all the other fields as you included request.FILES argument in it's constructor. In your models you have to define FooForm subclass of ModelForm class like this:
class FooForm(ModleForm):
Meta:
model = Foo
...where Foo is the subclass of Model, that describes the data you want to store persistently.