Invalid form when uploading file in Django - html

I need to upload file on a Django page, however, after following the official tutorial, I was not able to upload it, it always gives the error "invalid form", and when I tried to print out the error msg of the form, it says "This field is required".
One thing notable is: I have 2 forms on one page, one is this upload form and the other one is for filling out information. Not sure if this is the root cause.
I have tried all solutions provided on the Internet.
Template file:
<form id="uploadForm" action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<input type="file" value="upload" name="sourcefile">
<button type="submit">Upload</button>
</form>
Forms.py:
from django import forms
from .models import SourceFile
class UploadFileForm(forms.ModelForm):
class Meta:
model = SourceFile
fields = ('file', 'title')
Models.py:
from django.db import models
# Create your models here.
class SourceFile(models.Model):
title = models.CharField(max_length=255, blank=True)
file = models.FileField(upload_to="media/")
Views.py
def model_form_upload(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
instance = SourceFile(file_field=request.FILES['file'])
instance.save()
return JsonResponse({'error': False, 'message': 'Uploaded Successfully!'})
else:
print("Invalid form")
# return JsonResponse({'error': True, 'errors': form.errors})
else:
form = UploadFileForm()
return render(request, 'source_validation.html', {'form': form})

Your template is wrong. Either use {{ form.as_p }} which should display a file input field because file is a field in your form. (so remove the <input type="file" ...>)
Or don't use it and manually add the <input> fields, but then you must use the correct names. Your form expects a "file" parameter, not a "sourcefile" parameter:
<input type="file" name="file">
Also, you're overcomplicating things in your view (even though your current code will work if you fix your template):
if form.is_valid():
form.save() # this will save your model
return redirect(...)

Related

Issues in uploading image from user without django ModelForm

I am trying to create a form without using ModelForm. I using the input elements in HTML for the purpose (to upload name and image). But I am having trouble uploading images with this process.
The name is getting saved but not the image.
My code:
models.py
class Register(models.Model):
name = models.CharField(max_length=50, null=True)
idCard = models.FileField(upload_to='idCard', null=True)
views.py
def index(request):
if request.method == 'POST':
data.name = request.POST.get('name')
data.idCard = request.POST.get('idCard')
data.save()
return redirect('/')
return render(request, 'event/index.html')
index.html
<form class="mform" id="myform" method="POST" id="myform" action="" enctype="multipart/form-data">
{% csrf_token %}
<fieldset>
<legend>Registeration</legend>
<table cellspacing="0"><tbody>
<tr><td>
<label for="u_name"> Username :</label></td><td>
<input type="text" name="name" id="u_name">
<td>
</tr>
<tr><td>
<label for="u_img"> IDCard :</label></td><td>
<input type='file' accept='image/*' onchange='openFile(event)' name="idCard" id="u_img">
</td></tr>
The name is getting saved but not the image.
The files are stored in request.FILES:
def index(request):
if request.method == 'POST':
data.name = request.POST.get('name')
data.idCard = request.FILES.get('idCard')
data.save()
return redirect('/')
return render(request, 'event/index.html')
That being said, I strongly advise to use a Form (or ModelForm). A form does not just handle saving the object, it also performs proper validation, can return error messages, and removes a lot of boilerplate code. Often with some tweaking, you can let the form look like you want. But even if you manually write the form in the template, you can still use a form at the Django level to validate and save the object.

full_clean() missing 1 required positional argument: 'self'

I'm currently using django version 2.2.4 and trying to create an edit button that will update my models. When trying to save the updated value an TypeError occured which it stated that "full_clean() missing 1 required positional argument: 'self'". I can't seem to detect any error from my codes. Thanks in advance for helping me.
my views.py file
def lab_edit(request, pk, template_name='webapp/lab_edit.html'):
lab= get_object_or_404(Labs, pk=pk)
form = LabForm(request.POST or None, instance=Labs)
if request.method == "POST":
if form.is_valid():
form.save()
return redirect('lab')
return render(request, template_name, {'form':form})
my lab_edit.html file
<div class='container'>
<h2>EDIT LAB</h2>
<form method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
</div>
my LabForm
class LabForm(forms.ModelForm):
class Meta:
model = Labs
fields = ('labcode', 'name','administrator')
Your LabForm gets as instance= the model class, not a model object. You should fix that by passing lab instead:
def lab_edit(request, pk, template_name='webapp/lab_edit.html'):
lab = get_object_or_404(Labs, pk=pk)
if request.method == 'POST':
form = LabForm(request.POST, instance=lab)
if form.is_valid():
form.save()
return redirect('lab')
else:
form = LabForm(instance=lab)
return render(request, template_name, {'form':form})
By passing a reference to the class , you have basically called full_clean on the class, hence the error.
Note that you should not use request.POST or None since an empty POST request can still be a valid POST request.

Django upload form with different models

I am building my first Django app and I need to have an upload page where I would be able to upload multiple files in different upload forms. I need different forms and, I guess, models since depending on the form the file has to be stored in a respective folder in my media root and go through different further transformations. I also want different users have different levels of access to these uploads.
So far I have something like this (I have quite a bit of additional code inside functions in views.py that send data to data frames or other programs but I am not posting those:
models.py
class Upload(models.Model):
document = models.FileField(storage=OverwriteStorage(),upload_to=get_file_path)
upload_date=models.DateTimeField(auto_now_add =True)
class Upload_variables(models.Model):
variables = models.FileField(storage=OverwriteStorage(),upload_to=get_file_path_var)
upload_date=models.DateTimeField(auto_now_add =True)
forms.py
from django import forms
from uploader.models import Upload, Upload_variables
class UploadForm(forms.ModelForm):
class Meta:
model = Upload
fields = ('document',)
class UploadFormVar(forms.ModelForm):
class Meta:
model = Upload_variables
fields = ('variables',)
views.py
def home(request):
if request.method=="POST":
img = UploadForm(request.POST, request.FILES)
if img.is_valid():
img.save()
else:
img=UploadForm()
files=Upload.objects.all()
return render(request,'home.html',{'form':img})
def variables(request):
if request.method == 'POST':
var = UploadFormVar(request.POST, request.FILES)
if var.is_valid():
var.save()
else:
var = UploadFormVar()
files_st = Upload_variables.objects.all()
return render(request, 'home.html', {'form_b': var})
HTML
<form action="#" method="post" enctype="multipart/form-data">
{% csrf_token %} {{form}}
<input type="submit" value="Upload" id="submit_form"/>
</form>
<form action="#" method="post" enctype="multipart/form-data">
{% csrf_token %} {{form_b}}
<input type="submit" value="Upload" id="staging"/>
</form>
So I can see 2 Upload buttons but only one 'choose file'....
Thank you for your help!
Currently you are placing the forms in two separate views. You need to put them in the same view like this:
def home(request):
if request.method=="POST":
var = UploadFormVar(request.POST, request.FILES)
img = UploadForm(request.POST, request.FILES)
if img.is_valid():
img.save()
if var.is_valid():
var.save()
else:
img = UploadForm()
var = UploadFormVar()
files=Upload.objects.all()
return render(request,'home.html',{'form': img, 'form_b': var})

Not able to post form data to action url

I have a login form. After pressing the login button the the post data is sent to the view login_auth that authenticates the user data and redirects accordingly. However,after pressing the login button, I am not being redirected to the appropriate page.
views.py
def login_successful(request):
return render(request,"login_successful.html")
def login_invalid(request):
return render(request,"login_invalid.html")
def login(request):
return render(request,'login.html',c)
def loginauth(request):
username=request.POST.get("username",'')
password=request.POST.get("password",'')
user=auth.authenticate(username=username,password=password)
if user is not none:
user.login(request.user)
return redirect(login_successful)
else:
return redirect(login_invalid)
urls.py
urlpatterns = [
url(r'^registration/',views.registration),
url(r'^registration_successful/',views.registration_successful),
url(r'^home/',views.home),
url(r'^login/',views.login),
url(r'^login_successful/',views.login_successful),
url(r'^login_invalid/',views.login_invalid),
url(r'^login/auth',views.loginauth)
]
login.html
<html>
<form action="/login/auth" method="POST">{% csrf_token %}
Username :<input type="textbox" name="username" >
Password :<input type="password" name="password">
<input type="submit" value="Login">
</form>
</html>
Your login url pattern is missing a trailing $. It should be:
url(r'^login/$', views.login),
Without the dollar, the /login/auth is matched by r'^login/, so the request is handled by your login view.
It's a bit unusual to process the form on a different url. Django comes with authentication views, including a login view. I would recommend using this rather than writing your own.
Use name for url
views.py
def login_successful(request):
return render(request,"login_successful.html")
def login_invalid(request):
return render(request,"login_invalid.html")
def login(request):
return render(request,'login.html',c)
def loginauth(request):
username=request.POST.get("username",'')
password=request.POST.get("password",'')
user=auth.authenticate(username=username,password=password)
if user is not none:
user.login(request.user)
return redirect('login_successful')
else:
return redirect('login_invalid')
urls.py
urlpatterns = [
url(r'^registration/',views.registration),
url(r'^registration_successful/',views.registration_successful),
url(r'^home/',views.home),
url(r'^login/$',views.login),
url(r'^login_successful/',views.login_successful, name='login_successful'),
url(r'^login_invalid/',views.login_invalid, name='login_invalid'),
url(r'^login/auth',views.loginauth)
]

Django 'ManagementForm data is missing or has been tampered with' when saving modelForms with foreign key link

I am rather new to Django so this may be an easy question. I have 2 modelForms where there is a ForeignKey to another. My main goal is to save Indicators with a link to Disease (FK), such that for a particular disease, you can have multiple indicators.
With the code below, I get an error when I hit submit that says 'ManagementForm data is missing or has been tampered with'. Also, the code in views.py does not seem to be validating at the 3rd 'if' statement where there is a return HttpResponseRedirect. However, when I check my database, the values from the form have been written. Any ideas on why the error has been raised? and how to fix it?
My code is below:
models.py
#Table for Disease
class Disease(models.Model):
disease = models.CharField(max_length=300)
#Tables for Indicators
class Indicator(models.Model):
relevantdisease = models.ForeignKey(Disease)
indicator = models.CharField(max_length=300)
forms.py
class DiseaseForm(forms.ModelForm):
class Meta:
model = Disease
class IndicatorForm(forms.ModelForm):
class Meta:
model = Indicator
DiseaseFormSet = inlineformset_factory(Disease,
Indicator,
can_delete=False,
form=DiseaseForm)
views.py
def drui(request):
if request.method == "POST":
indicatorForm = IndicatorForm(request.POST)
if indicatorForm.is_valid():
new_indicator = indicatorForm.save()
diseaseInlineFormSet = DiseaseFormSet(request.POST, request.FILES, instance=new_indicator)
if diseaseInlineFormSet.is_valid():
diseaseInlineFormset.save()
return HttpResponseRedirect('some_url.html')
else:
indicatorForm = IndicatorForm()
diseaseInlineFormSet = DiseaseFormSet()
return render_to_response("drui.html", {'indicatorForm': indicatorForm, 'diseaseInlineFormSet': diseaseInlineFormSet},context_instance=RequestContext(request))
template.html
<form class="disease_form" action="{% url drui %}" method="post">{% csrf_token %}
{{ indicatorForm.as_table }}
<input type="submit" name="submit" value="Submit" class="button">
</form>
You have neither diseaseFormSet nor diseaseFormSet's management form in your template, yet you try to instantiate the formset. Formsets require the hidden management form which tells django how many forms are in the set.
Insert this into your HTML
{{ diseaseFormSet.as_table }}
{{ diseaseFormSet.management_form }}