In my django application the form never returns true even if I add the same data as in the admin application. My model.py looks like:
from django.db import models
from django.db.models import ImageField, signals
from django.dispatch import dispatcher
from django.forms import ModelForm
# Create your models here.
class Image(models.Model):
emailAddress = models.EmailField(max_length=75)
image = ImageField(upload_to='photos')
caption = models.CharField(max_length=100)
class UploadForm(ModelForm):
class Meta:
model = Image
My views.py looks like:
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render_to_response
from competition.models import Image, UploadForm
# Create your views here.
def index(request):
images = Image.objects.all().order_by('emailAddress')
return render_to_response('images/index.html', {'images': images})
def uploadImage(request):
if request.method == 'POST': # If the form has been submitted...
form = UploadForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
emailAddress = form.cleaned_data['emailAddress']
image = form.cleaned_data['image']
caption = form.cleaned_data['caption']
i = Image(emailAddress=emailAddress, image = image, caption = caption)
i.save()
return HttpResponseRedirect('../image/')
else:
return render_to_response('images/upload.html', {'form': form})
else:
form = UploadForm() # An unbound form
return render_to_response('images/upload.html', {'form': form})
My template looks like:
<html>
<body>
<form enctype="multipart/form-data" action="/image/uploadImage" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
</body>
</html>
I can get it work correctly if I use the admin application but need a generic form and this does't work as it keeps asking for a either the email address or image (the error appears above the image field). So why might my form not be valid?
You need to instantiate your form with request.FILES as well as request.POST.
As an aside, you can save the model form instead of creating the Image by hand in the view.
You have a required image but you aren't binding the file data to the form.
form = UploadForm(request.POST)
should be
form = UploadForm(request.POST, request.FILES)
See https://docs.djangoproject.com/en/1.3/ref/forms/api/#binding-uploaded-files
FileField and ImageField fields have two places need to notice:
Require enctype="multipart/form-data" in form element.
<form enctype="multipart/form-data" method="post" action="/foo/">
Require request.FILES for form constructor.
form = UploadFileForm(request.POST, request.FILES)
Please refer:
https://docs.djangoproject.com/en/2.2/topics/http/file-uploads/
https://docs.djangoproject.com/en/2.2/ref/forms/api/#binding-uploaded-files
Related
I'm trying to make a workflow where the user enters data on one page, then has to check the data and tick a tickbox to accept the T&C's. So the code has to check that the checkbox is checked before going on, but doesn't care until the second step.
It's not a bound field and I think that's the problem - I don't need a model just to handle a workflow, and I don't want to have to store, in a database, a simple ephemeral field in a form!
I'm running Django 2.1.5.
I've tried every possible combination of:
test_form.fields['tickbox'].value - doesn't exist, which is ridiculous
test_form.fields['tickbox'] == False - value doesn't change at all
request.POST['tickbox'] seems to go missing?
views.py
from django.http import HttpResponse
from django.template import loader
from django.forms import Form, CharField, BooleanField
class test_form(Form):
name = CharField()
tickbox = BooleanField(required=False, initial=False)
def testview(request):
if request.method == 'POST':
testform = test_form(request.POST)
if testform.fields['tickbox'] == True:
do_things()
else:
dont_do_things()
else:
testform = test_form()
template = loader.get_template('testform.html')
context = { 'testform : userform,
}
return HttpResponse(template.render(context, request))
I should be able to test the value of the field and get a changing response depending on if the user has ticked the box or not - I seem to get True regardless?
Here is a way how to solve your issue using Class Based Views and Function Based Views:
So, first:
forms.py:
from django import forms
class CheckboxForm(forms.Form):
name = forms.CharField()
tickbox = forms.BooleanField(required=False, initial=False)
def clean_tickbox(self):
'''Here we can check if the checkbox is checked or not'''
tickbox = self.cleaned_data.get('tickbox')
if not tickbox:
# Raise an error if the checkbox is not checked
raise forms.ValidationError("You must select this option")
# And return the value
return tickbox
With a class based view:
views.py:
from django.views import View
from django.contrib import messages
class CheckboxView(View):
template_name = 'checkbox.html'
form_class = forms.CheckboxForm
def get(self, request, *args, **kwargs):
form = self.form_class()
return render(request, self.template_name, {'form': form})
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
# check if the form is valid
if form.is_valid():
# Use Django builtin messages framework
messages.success(request, "Checked!")
else:
messages.error(request, "not checked!")
return render(request, self.template_name, {'form': form})
With function based views:
from django.contrib import messages
def checkbox_func(request, *args, **kwargs):
template = 'checkbox.html'
if request.method == 'POST':
form = forms.CheckboxForm(request.POST)
# Check if the form is valid
if form.is_valid():
messages.success(request, "Checked!")
else:
messages.error(request, "Not checked!")
else:
form = forms.CheckboxForm()
return render(request, template, {'form': form})
urls.py:
from django.urls import path
from YOUR_APP import views
urlpatterns = [
# ... Your URLS
# Class Based Views
path('checkbox/', views.CheckboxView.as_view(), name="checkbox"),
# Function Based Views
path('checkbox2/', views.checkbox_func, name="checkbox_v2")
]
And your template: checkbox.html:
{% for message in messages %}
{{message}}
{% endfor %}
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Submit</button>
</form>
Demo:
First of all, yes it is perfectly possible to have FormFields without them being declared in a Model.
You seem to be trying to do form validation on your own when django already handles simple cases like this for you. Let's start by looking at the documentation of BooleanField:
Validates that the value is True (e.g. the check box is checked) if
the field has required=True
Since that is exactly what you want to validate we can change the field definition:
tickbox = BooleanField(required=True, initial=False)
Since the documentation told us that django takes care of validating that the checkbox is actually checked there is no need for the custom validation code anymore. Let's look at the view next and refactor it:
def testview(request):
if request.method == 'POST':
testform = test_form(request.POST)
# check if the form is valid (that includes the checkbox being checked)
if testform.is_valid():
do_things()
else:
dont_do_things()
else:
testform = test_form()
template = loader.get_template('testform.html')
context = {'testform': userform} # added a closing single tick
return HttpResponse(template.render(context, request))
So instead of doing custom validation you just call the .is_valid() method of your Form instance to run validation. If you want to access any of the fields instead of using testform.fields[fieldname] you'd do testform.cleaned_data[fieldname] which only accesses fields that have been validated.
For more information on form processing in general I highly recommend reading through django's Working with forms.
I simply use the "cleaned_data" to check if the field is not part of the model but its just a form field.
so in your case this will be in your view
if testform.cleaned_data['tickbox'] == True:
do_things()
else:
dont_do_things()
I am trying to show a newsletter form, and it is not shown in the page
This is my models.py
from django.db import models
# Create your models here.
class newsletter_user(models.Model):
email = models.EmailField()
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.email
This is my forms.py
from django import forms
from .models import newsletter_user
class newsletterForm(forms.ModelForm):
class Meta:
model = newsletter_user
fields = ['email']
def clean_email(self):
email = self.cleaned_data.get('email')
return email
This is my admin.py
from django.contrib import admin
from .models import newsletter_user
# Register your models here.
class newsletterAdmin(admin.ModelAdmin):
list_display = ('email','date_added',)
admin.site.register(newsletter_user,newsletterAdmin)
This is the views.py
from django.shortcuts import render
from .models import newsletter_user
from .forms import newsletterForm
# Create your views here.
def newsletter_subscribe(request):
form = newsletterForm(request.POST or none)
if form.is_valid():
instance = form.save(commit=false)
if newsletter_user.objects.filter(email=instance.email).exists():
print("already exists")
else:
instance.save()
context = {'form':form,}
template = "/blog/templates/footer.html"
return render(request, template, context)
This is the html
<form method="post" action=''>
<div class = "input-group">
{{form}} {% csrf_token %}
<span class = "input-group-btn">
<button class="btn btn-default" type="submit">Subscribe</button>
</span>
</div>
</form>
This is my urls.py
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', views.BlogIndex.as_view(), name='home'),
url(r'^(?P<slug>[-\w]+)/$', views.BlogDetail.as_view(), name='entry_detail'),
url(r'^ckeditor/', include('ckeditor_uploader.urls')),
url(r'^footer/$', subscribe_views.newsletter_subscribe, name='subscribe'),
]
My Project directory
The button is shown
But the form is not shown..
This is my source in web browser RIGHT-CLICK->VIEW SOURCE
The url router will send the request to the first matching view. That is the only one that is called, and that view has to provide the context data that the template consumes. (You can also write your own context processor to insert context that you need everywhere.)
Since another pattern also matches /footer/, your request is clearly handled by some other view.
url(r'^(?P<slug>[-\w]+)/$', views.BlogDetail.as_view(), name='entry_detail'),
If the other view doesn't provide form into the context, there's nothing for Django to render.
Your view function newsletter_detail() is not called from other views, so that context is not used. (Using the undefined none there would have caused a run time error, which shows that the code was never evaluated.)
Catch-all routes such as entry_detail should either be used as the last url route, or be made more specific. Something like r'^/blog/(?P<slug>[-\w]+)/$', for instance, which will not match /footer/.
For a simple "subscribe" form in the footer, I recommend writing it as just html, and set up a route /subscribe/ to handle POST requests. There's not anything to gain by using Django's form framework for such a simple case (Just one field).
The django docs has an example of how you can implement something like this.
You footer.html template fragment should not require any context that is not automatically inserted by a context processor. Django's CsrfViewMiddleware provides the {% csrf_token %}, so that's an example of something you can use in template fragments such as a footer.
If you need some complicated form in your footer, you can write custom middleware to insert a Django Form instance in every context, (but you should probably give it a less generic name than form).
You may need to make some changes in your view somewhat like this,
def newsletter_subscribe(request):
if request.method == 'POST':
form = newsletterForm(request.POST)
if form.is_valid():
instance = form.save(commit=false)
if newsletter_user.objects.filter(email=instance.email).exists():
print("already exists")
else:
instance.save()
else:
form = newsletterForm()
context = {'form':form,}
template = "/blog/templates/footer.html"
return render(request, template, context)
You only need to initialise the form with request.POST , if request method is actually "POST". Else, just initialise a blank form.
I am new to django, I am trying to upload more than one file from the browser and store them somewhere in computer storage but I am not storing them successfully with this code please help me out to find my mistake or improvements that I can do. Thanks in advance to help.
views.py
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
def Form(request):
return render(request, "index/form.html", {})
def Upload(request):
for count, x in enumerate(request.FILES.getlist("files")):
def process(f):
with open('/Users/benq/djangogirls/upload/media/file_' + str(count), 'wb+') as destination:
for chunk in f.chunks():
destination.write(chunk)
process(x)
return HttpResponse("File(s) uploaded!")
app/urls.py
from django.conf.urls import url
from index import views
urlpatterns = [
url(r'^form/$', views.Form),
url(r'^upload/$', views.Upload)
]
form.html
<form method="post" action="../upload/" entype="multipart/form-data"> {% csrf_token %}
<input type="file" name="files" multiple />
<input type="submit" value="Upload" />
my model to save Document
class Document(models.Model):
file = models.FileField('Document', upload_to='mydocs/')
#property
def filename(self):
name = self.file.name.split("/")[1].replace('_',' ').replace('-',' ')
return name
def get_absolute_url(self):
return reverse('myapp:document-detail', kwargs={'pk': self.pk})
you can try a django create view in my code i use this DocumentCreateView
class DocumentCreate(CreateView):
model = Document
fields = ['file']
def form_valid(self, form):
obj = form.save(commit=False)
if self.request.FILES:
for f in self.request.FILES.getlist('file'):
obj = self.model.objects.create(file=f)
return super(DocumentCreate, self).form_valid(form)
my form html file
<script>
$(document).ready(function(){
$('#id_file').attr("multiple","true");
})
</script>
<form method="post" enctype="multipart/form-data" action="">{% csrf_token %}
{{ form.file }}
<input type="submit" value="upload" />
</form>
Answer from official django documentation
file_field = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
https://docs.djangoproject.com/en/3.0/topics/http/file-uploads/#uploading-multiple-files
views.py
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
def Form(request):
for x in request.FILES.getlist("files"):
def process(f):
with open('/Users/benq/djangogirls/upload/media/file_' + str(x), 'wb+') as destination:
for chunk in f.chunks():
destination.write(chunk)
process(x)
return render(request, "index/form.html", {})
urls.py
from django.conf.urls import url
from index import views
urlpatterns = [
url('form', views.Form),
]
worked for me.
Just an update from Django 3.2 and above. According to docs you have to:
If you want to upload multiple files using one form field, set the multiple HTML attribute of field’s widget:
from django import forms
class FileFieldForm(forms.Form):
file_field = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
Then override the post method of your FormView subclass to handle multiple file uploads:
from django.views.generic.edit import FormView
from .forms import FileFieldForm
class FileFieldView(FormView):
form_class = FileFieldForm
template_name = 'upload.html' # Replace with your template.
success_url = '...' # Replace with your URL or reverse().
def post(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
files = request.FILES.getlist('file_field')
if form.is_valid():
for f in files:
... # Do something with each file.
return self.form_valid(form)
else:
return self.form_invalid(form)
I was able to solve the multi uploads portion in the create view here: Django Class based UpdateView with Form for Multiple Uploaded Files , however, now the update get function is what I am currently stuck on.
I have a model in Django with a foreign key to Django User Model. I am trying to update my model with a form, but database isn't updating. I can't figure out the problem.
model.py
from django.conf import settings
class UserInfo(models.Model):
username = models.CharField(max_length = 30)
owner = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE,)
form.py
from django import forms
from society.models import UserInfo
class Editform(forms.ModelForm):
username=forms.CharField(widget=forms.TextInput(attrs={'onchange': 'this.form.submit();', 'class': 'editinput'}))
class Meta:
model = UserInfo
fields ='__all__'
views.py
from django.shortcuts import render
from society.models import UserInfo
from django.contrib.auth.models import User
from society.forms import Editform
def ProfileView(request):
user = request.user
username = UserInfo.objects.get(owner=user)
if request.method == 'POST':
form = Editform(request.POST, instance=username)
if form.is_valid():
form.save()
else:
form = Editform(instance=username)
return render (request, 'profile_view.html', {'user':username, 'form':form})
url.py
from django.conf.urls import url
from django.contrib import admin
import society.views
urlpatterns = [
url(r'^$', 'society.views.home'),
url(r'^admin/', admin.site.urls),
url(r'^login/', 'django.contrib.auth.views.login'),
url(r'^logout/', 'django.contrib.auth.views.logout'),
url(r'^userreg/', 'society.views.UserReg'),
url(r'^profile/', 'society.views.ProfileView'),
]
profile_view.html
<div>
<form method="POST">
{% csrf_token %}
{{form.username}}
{{user.username}}
</form>
</div>
When ever I change form.username, user.username change instantly but the database is not updating. I tried with adding a submit button, but still no luck.
You should pass record id for updating existing UserInfo record.
from django.shortcuts import render
from society.models import UserInfo
from django.contrib.auth.models import User
from society.forms import Editform
def ProfileView(request):
user_id = request.POST.get('user_id')
user = UserInfo.objects.get(pk=user_id)
if request.method == 'POST':
form = Editform(request.POST, instance=user)
if form.is_valid():
form.save()
else:
form = Editform(instance=user)
return render (request, 'profile_view.html', {'user':username, 'form':form})
You can update in 2 method for eg: here i am going to update Your username,
1) if you using object.get():
get_name = UserInfo.objects.get(owner=user)
get_name['username'] = 'Your Input what you need to change'
get_name.save()
2) if you using object.filter():
get_name = UserInfo.objects.filter(owner=user).update(username='your data') # or form.username
Thats it..
Apart from anything else, you haven't pointed your form at anything, so the form can't connect to the logic of the view - in effect, you've specified the form should POST content, but not where to.
The form should point to a URL in your urls.py file, which is of course linked to the view you've shown above. That works in the following way:
<form action="{% url 'core.views.new_comment' %}" method="post">
{% csrf_token %}
...
</form>
There's more guidance about how this works here in the docs. (Obviously people know that the answer's in the docs, the trick is finding it. :) )
(Also, your formatting is off in the views.py, but I think that's just a cut and paste problem when entering the question.)
Anyway I soloved this problem, Thank You everyone. Just Changed the form.py
from django import forms
from society.models import UserInfo
class Editform(forms.ModelForm):
username=forms.CharField(widget=forms.TextInput(attrs={'onchange': 'this.form.submit();', 'class': 'editinput'}))
class Meta:
model = UserInfo
exclude =('owner',)
As owner is a mandatory field, but I omitted it from template it was showing mandatory field error. Its working now. Thanks anyway.
I'm having a problem with saving and updating a value to my database.
View:
def code_prof_edit(request, ampCode):
user_code = get_object_or_404(CodeUser, pk=ampCode)
if request.method =='POST':
form = CodeUserForm(request.POST, instance=user_code)
if form.is_valid():
form.save()
return HttpResponseRedirect('/codes/' + user_code.ampCode)
else:
form = CodeUserForm(instance=user_code)
return render_to_response('edit_code_user.html', {'user_code':user_code, 'form':form})
Relevant template form tag:
<form action="." method="POST"> {% csrf_token %}
{{form.as_p}}
<input type="submit" value="Save" />
</form>
Using the post method, the form correctly renders in the browser with all of the original values pre-populated, but if I change the values and click submit, none of the changes are made. Everything seems to work correctly in that the user is redirected to the correct page which means the save must have been called, but the info typed isn't being saved. Any and all help would be appreciated.
Edit entire view function:
from django.shortcuts import render_to_response, get_object_or_404
from django.http import *
from django.template import RequestContext
from codeuser.models import CodeUser
from codeuser.forms import CodeUserForm
import pdb
def code_prof_edit(request, ampCode):
user_code = get_object_or_404(CodeUser, pk=ampCode)
if request.method =='POST':
pdb.set_trace()
form = CodeUserForm(request.POST, instance=user_code)
if form.is_valid():
form.save()
return HttpResponseRedirect('/codes/' + user_code.ampCode)
else:
return render_to_response('home.html')
else:
form = CodeUserForm(instance=user_code)
return render_to_response('edit_code_user.html', {'user_code':user_code, 'form':form})
Edit: Figured it out. In the html form tag, the action attribute was incorrect. "." wasn't working, I needed "./edit" to get the correct result. Also, excluding that attribute all together worked perfectly too.