Halo, i'm trying to upload a file using filefield. But i always failed. when statement form.errors.as_data() executed, the browser return 'tempfile'. I already trying to find solution from django documentation and some django references. But, still can't fix it. ;(
Here's my view.py
def dataprocessing(request):
if request.method == 'POST':
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
import pdb; pdb.set_trace()
newdoc = Document(docfile=request.FILES['myfile'])
newdoc.save()
#Redirect to the dataprocessing after POST
#return render(request, 'dataprocessing.html')
return HttpResponse("success")
else:
return HttpResponse(form.errors.as_data())
else:
import pdb; pdb.set_trace()
form = DocumentForm() #A empty, unbound form
return render(request, 'dataprocessing.html', {'form': form})
models.py
class Document(models.Model):
docfile = models.FileField(upload_to='documents/%Y/%m/%d')
forms.py
class DocumentForm(forms.Form):
tempfile = forms.FileField()
And dataprocessing.html
<form method="post" enctype="multipart/form-data" action="{% url "dataprocessing" %}">
<div class="form-group">
<label for="up">Input Data</label> {% csrf_token %}
<input type="file" name=myfile class="filestyle" data-buttonName="btn-primary" data-buttonBefore="true" data-size="sm" accept="application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
id="up">
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary btn-block">Upload Data</button>
<button type="button" class="btn btn-primary btn-block">Download Template</button>
</div>
</form>
How about using forms.ModelForm instaed forms.Form like this?
# forms.py
class DocumentForm(forms.Model):
class Meta:
model = Document
fields = ['tempfile']
and make your views.py like this:
# views.py
def dataprocessing(request):
if request.method == 'POST':
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return HttpResponse("success")
else:
return HttpResponse(form.errors.as_data())
else:
form = DocumentForm() #A empty, unbound form
return render(request, 'dataprocessing.html', {'form': form})
This makes form object can be saved directly to your model.
Related
I was trying to create a blog app by following an online Django tutorial and while I was testing the sign-up page, I ran into a Value Error saying that the view did not return a HTTP response object. i tried everything but i could not find the answer as i am not a Django expert
in the users app's views.py file was the code that threw the error
from django.shortcuts import render, redirect
from django.contrib.auth.forms import UserCreationForm
from django.contrib import messages
def register(request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
username = form.cleaned_data.get('username')
messages.success(request, f'Account Created for {username}')
return redirect('blog-home')
else:
form = UserCreationForm()
return render(request, 'users/register.html', {'form': form})
and this is the register template
{% extends "myblog/base.html" %}
{% block content %}
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">
Join Today!
</legend>
{{ form.as_p }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">
Sign Up!
</button>
</div>
</form>
<div class="border-top pt-3">
<small class="text-muted">
Already Have an account?
Sign In!
</small>
</div>
</div>
{% endblock content%}
And this is the file structure of the project
File Structure
If we have a POST request, and the form is not valid, you do not return anything. Unindent the render call, so:
def register(request):
if request.method == 'POST':
form = UserCreationForm(request.POST, request.FILES)
if form.is_valid():
username = form.cleaned_data.get('username')
messages.success(request, f'Account Created for {username}')
return redirect('blog-home')
else:
form = UserCreationForm()
return render(request, 'users/register.html', {'form': form})
You can write function like this ...
def register(request):
form = UserCreationForm()
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
username = form.cleaned_data.get('username')
messages.success(request, f'Account Created for {username}')
return redirect('blog-home')
else:
form.errors
context = {'form': form}
return render(request, 'users/register.html', context)
return something for the function register also , you are returning only in if else conditions
return render(request, 'users/register.html', {'form': form}) add this at the end of the function outiside if else (now we have returned something for the function register also , you are returning only in if else conditions
I have an update form to update information. Here problem is, product_title is updating but product_image is not working. Where is the problem that's for why the photo is not updating?
views.py:
def update_product(request,id):
product = Products.objects.get(pk=id)
form = update_product_info(request.POST or None, instance=product)
if request.method == 'POST' and form.is_valid():
form.save()
print(form.errors)
messages.success(request,"Successfully product information updated.")
return redirect("my_products")
context = {
'product':product,
"form":form
}
return render(request, "update_product.html", context)
update form:
class update_product_info(forms.ModelForm):
class Meta:
model = Products
fields = ('product_title','product_image')
widgets = {
'product_title':forms.TextInput(attrs={'class':'form-control', 'style':'font-size:13px;'}),
'product_image':forms.FileInput(attrs={'class':'form-control', 'style':'font-size:13px;'})
}
template:
<form action="" method="POST" class="needs-validation" style="font-size: 13px;" novalidate="" autocomplete="off" enctype="multipart/form-data">
{% csrf_token %}
{{form.as_p}}
<div class="d-flex align-items-center">
<button type="submit" class="btn btn-outline-dark ms-auto" value="Update" style="font-size: 13px;">Add</button>
</div>
You should pass both request.POST and request.FILES to the form:
from django.shortcuts import get_object_or_404
def update_product(request, id):
product = get_object_or_404(Products, pk=id)
if request.method == 'POST':
form = update_product_info(request.POST, request.FILES, instance=product)
if form.is_valid():
form.save()
messages.success(request, 'Successfully product information updated.')
return redirect('my_products')
else:
form = update_product_info(instance=product)
context = {'product': product, 'form': form}
return render(request, 'update_product.html', context)
Note: It is often better to use get_object_or_404(…) [Django-doc],
then to use .get(…) [Django-doc] directly. In case the object does not exists,
for example because the user altered the URL themselves, the get_object_or_404(…) will result in returning a HTTP 404 Not Found response, whereas using
.get(…) will result in a HTTP 500 Server Error.
Note: normally a Django model is given a singular name, so Product instead of Products.
Note: Usually a Form or a ModelForm ends with a …Form suffix,
to avoid collisions with the name of the model, and to make it clear that we are
working with a form. Therefore it might be better to use ProductInfoForm instead of
update_product_info.
I'm trying to make model based form but something went wrong.
model:
class Topic(models.Model):
name = models.CharField(max_length=200)
icon = models.ImageField(upload_to = 'images/')
form:
class TopicCreationForm(ModelForm):
class Meta:
model = Topic
fields = '__all__'
view:
def TopicCreateView(request):
form = TopicCreationForm()
if request.method == 'POST':
form = TopicCreationForm(request.POST)
if form.is_valid():
form.save()
return redirect('home')
else:
print('aaa') # It displays in console
context = {'form':form}
return render(request, 'blog/topic_form.html', context)
my form html part
<form method="POST">
{% csrf_token %}
<fieldset >
<legend> New Topic</legend>
{{ form|crispy }}
</fieldset>
<div>
<input type="submit" value="submit" class="button-33" role="button">
</div>
</form>
where did i make mistake ?
You need to pass both request.POST and request.FILES [Django-doc], so:
def topic_create(request):
if request.method == 'POST':
form = TopicCreationForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('home')
else:
print('aaa') # It display in console
else:
form = TopicCreationForm()
context = {'form':form}
return render(request, 'blog/topic_form.html', context)
In the HTML form, you need to specify that the files should be encoded with the enctype="…" attribute [mdn]:
<form method="post" enctype="multipart/form-data">
…
</form>
I want to upload only button and don't need refresh when upload how to fix this
model_form_upload.html
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" >Upload</button>
</form>
forms.py
class DocumentForm(forms.ModelForm):
class Meta:
model = DocumentFile
fields = ['document']
views.py
def model_form_upload(request):
if request.method == 'POST':
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('home')
else:
form = DocumentForm()
print(form)
return render(request, 'model_form_upload.html', {'form': form})
I have a standard Form to edit an object that has a file field in it. When I add a new profile, everything works fine, but when I want to modify a field, then problems happen: when I don't include request.FILES, all fields get retrieved in the form and can be updated with no problems, except the avatar (filefield), but when I add the request.FILES, fields are no longer retrieved in the inputs, and the form is not valid. What am I doing wrong?
models.py:
from django.db import models
class Profile(models.Model):
name = models.CharField(max_length=45)
email = models.EmailField()
avatar = models.FileField(upload_to="avatars/")
def __str__(self):
return self.name
forms.py:
from django import forms
from .models import Profile
class EditUserForm(forms.ModelForm):
class Meta:
model = Profile
fields = ["name", "email", "avatar"]
profile.html:
<form method="POST">
{% csrf_token %}
<div class="col-md-12">
<div class="row border m-3 p-5">
<div class="col-md-6">Name</div>
<div class="col-md-6">{{ form.name }}</div>
</div>
<div class="row border m-3 p-5">
<div class="col-md-6">Email</div>
<div class="col-md-6">{{ form.email }}</div>
</div>
<div class="row border m-3 p-5">
<div class="col-md-6">Avatar</div>
<div class="col-md-6">
<img src="{{ profile.avatar.url }}" width="100rem" />
{{ form.avatar }}
</div>
</div>
<div class="row">
<button type="submit" class="btn btn-success">Save</button>
</div>
</div>
</form>
views.py:
def profile(request, pk):
profile_instance = Profile.objects.get(id=pk)
form = EditUserForm(request.POST, request.FILES, instance = profile_instance)
context = {
'profile': profile_instance,
'form': form,
}
if request.method == "POST":
if form.is_valid():
profile = form.save(commit=False)
profile.save()
else:
print("form not valid")
else:
return render(request, "app/profile.html", context)
return render(request, "app/profile.html", context)
Special thank's to #bruno desthuilliers and #dirkgroten.
Here is the answer to solve the 2 problems:
def profile(request, pk):
if request.method == 'POST':
form = EditUserForm(request.POST, request.FILES, instance = Profile.objects.get(id=pk))
if form.is_valid():
profile = form.save(commit=False)
profile.save()
return redirect('profile', pk)
else:
form = EditUserForm(instance = Profile.objects.get(id=pk))
context = {
'profile': Profile.objects.get(id=pk),
'form': form,
}
return render(request, "app/profile.html", context)
Try refactoring the code as follows: (edit it if I missed something. After form.is_valid, the same form should be sent in the context to display the errors.
def profile(request, pk):
profile_instance = Profile.objects.get(id=pk)
form = EditUserForm(instance = profile_instance)
if request.method == "POST":
form = EditUserForm(request.POST, request.FILES, instance = profile_instance)
if form.is_valid():
profile = form.save(commit=False)
profile.save()
form = EditUserForm(instance = profile_instance)
context = {
'profile': profile_instance,
'form': form,
}
return render(request, "app/profile.html", context)