Django, how to include pre-existing data in update form view - django

I am unable to see pre-existing form data when updating. The forms work fine, after submitting the database is updated, but in order to submit the user must enter all form data (including data that will not be updated). While reentering, the previous data is not visible. Is there a way to display the current data of the model instance being updated in the form fields?
Forms:
UpdateSomethingForm(forms.ModelForm):
class Meta:
model = Something
fields = ['field1', 'field2', 'field3']
Views:
def update_something(request, object_pk):
form = UpdateSomethingForm()
context_dict = {}
try:
instance = Something.objects.get(pk=object_pk)
context_dict['instance'] = instance
except Something.DoesNotExist:
context_dict['instance'] = None
if request.method == 'POST':
form = UpdateSomethingForm(request.POST, instance=instance)
if form.is_valid():
form.save(commit=True)
return HttpResponseRedirect('/home')
else:
print(form.errors)
context_dict['form'] = form
return render(request, 'form.html', context=context_dict)
Html:
<form role="form" method="post">
{% csrf_token %}
{{ form|bootstrap }}
<div class="form-group">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>

You passed the instance argument on POST, but not on GET.
form = UpdateSomethingForm(instance=instance)
in full:
def update_something(request, object_pk):
try:
instance = Something.objects.get(pk=object_pk)
except Something.DoesNotExist:
instance = None
if request.method == 'POST':
form = UpdateSomethingForm(request.POST, instance=instance)
if form.is_valid():
form.save()
return HttpResponseRedirect('/home')
else:
form = UpdateSomethingForm(instance=instance)
context_dict = {'form': form, 'instance': instance}
return render(request, 'form.html', context_dict)

The main problem is that you construct an empty Form, even if the instance can be found. But you make the view rather "chaotic" in the first place.
Probably a more readable view is:
def update_something(request, object_pk):
context_dict = {}
try:
instance = Something.objects.get(pk=object_pk)
except Something.DoesNotExist:
instance = None
context_dict['instance'] = instance
if request.method == 'POST':
form = UpdateSomethingForm(request.POST, instance=instance)
if form.is_valid():
form.save(commit=True)
return redirect('view_name')
else:
form = UpdateSomethingForm(instance=instance)
context_dict['form'] = form
return render(request, 'form.html', context=context_dict)
Here we ensure that the instance variable is always defined, also in the case the except body is "firing".
Furthermore it is probably better to use a redirect(..) and pass the name of the view over an URL, since if you change the URL of that view, this will still work.

Related

How to upload file in django

this might be a pretty stupid question. Also I am new to django. But I was trying to create a basic file upload approach with django where user uploads a file and it gets stored into the defined media path (or whatever that it's called) and that the file size, name, and some other attributes that are needed can be stored into the database. So I have the model ready which will help you understand the question better.
class Document(models.Model):
file_uid = models.CharField(max_length = 16)
file_name = models.CharField(max_length = 255)
file_size = models.CharField(max_length = 255)
file_document = models.FileField(upload_to='uploaded_files/')
uploaded_on = models.DateTimeField(auto_now_add=True)
uploaded_by = models.CharField(max_length=16)
Now it's clearly plain that we don't need to create all the fields in the form and that most them can be received from the file itself (like the name, size). for other attrs like uid and uploaded by those also will be added by the backend. So that's where I am stuck. I have searched for 2 days straight and still couldn't find a proper solution.
As of now this is my views.py
def uploadView(request):
if(request.method == 'POST'):
form = FileUploadForm(request.POST, request.FILES)
uploaded_file = request.FILES['uploaded_file']
file_dict = {
'file_uid' : get_random_string(length=10),
'file_name' :uploaded_file.name,
'file_size' : uploaded_file.size,
'file_document' : request.FILES['uploaded_file'],
'uploaded_by' : get_random_string(length=10)
}
form = FileUploadForm(data=file_dict)
if form.is_valid():
form.save()
return HttpResponse("You reached here")
else:
return HttpResponse("Your form is invalid")
else:
form = FileUploadForm(request.POST, request.FILES)
return render(request, 'function/upload.html', {
'form':form
})
I don't know if this is correct but as of know the form.isvalid() is false.
here's my forms.py
class FileUploadForm(forms.ModelForm):
file_document = forms.FileField(widget=forms.FileInput(attrs={'name':'uploaded_file'}))
class Meta:
model = Document
fields = ('file_uid', 'file_name', 'file_size', 'file_document', 'uploaded_by')
and my upload page section looks like this
<body>
<h1>Upload a file</h1>
<form action="" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<input type="file" name="uploaded_file">
<button type="submit">Upload</button>
</form>
</body>
If you can mercifully guide me into a proper way of doing this i'll be really gratefull.
Before solution, Here are few issues i found in your code
Major issue is how you tried to update the name of your file_document input, it doesn't work this way. confirm this by inspecting in devtools.
Checkout my answer here to update name attribute of django input form field.
Without updating this, you are not getting file from form.
Not issues just something i would like to point out
def uploadView(request):
if(request.method == 'POST'):
form = FileUploadForm(request.POST, request.FILES)
# your code in between, here the above form is never used and the overridden by the form in next line so why assigning it
form = FileUploadForm(data=file_dict)
# your form.is_valid() code start here
else:
form = FileUploadForm(request.POST, request.FILES)
# This block will only run for GET request, why using request.POST, request.FILES
return render(request, 'function/upload.html', {
'form':form
})
Here is how i got your code working
update FileUploadForm like this
class FileUploadForm(forms.ModelForm):
class Meta:
model = Document
fields = ('file_uid', 'file_name', 'file_size', 'file_document', 'uploaded_by')
# below code is only used to change the name of file_document to uploaded_file
custom_names = {'file_document': 'uploaded_file'}
def add_prefix(self, field_name):
field_name = self.custom_names.get(field_name, field_name)
return super(FileUploadForm, self).add_prefix(field_name)
use form in html like this
<form method="POST" action="" enctype="multipart/form-data">
{% csrf_token %}
{{form.file_document}}
<input type="submit" value="send"/>
</form>
Update view as
def uploadView(request):
if(request.method == 'POST'):
uploaded_file = request.FILES['uploaded_file']
file_dict = {
'file_uid' : 'test1',
'file_name' :uploaded_file.name,
'file_size' : uploaded_file.size,
'uploaded_by' : 'hemant'
}
form = FileUploadForm(file_dict, request.FILES)
if form.is_valid():
form.save()
return HttpResponse("You reached here")
else:
return HttpResponse("Your form is invalid")
else:
form = FileUploadForm()
return render(request, 'function/upload.html', {
'form':form
})

Form not registering photo Django 3.0

I'm trying to get a photo to upload and the form is not seeing the file and in the form.errors, it says 'this field is required'. I've tried using picture = request.FILES['picture'] to no avail and have also tried picture = form.FILES['picture'] as well as picture = request.POST.FILES['picture'] and picture = form.cleaned_data.get('picture') What am I missing? Let me know if you need anymore information
template
{% block content %}
<h1>Create {{post_type.title}} Post</h1>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{form.as_p}}
<button type='submit'>Submit</button>
</form>
{% endblock %}
forms.py
class PicturePostForm(forms.ModelForm):
class Meta:
model = PicturePost
fields = ('description', 'privacy', 'picture', 'categories')
views.py
#login_required()
def picture_post(request):
"""
Creates new picture post
"""
if request.method == "POST":
form = PicturePostForm(request.POST)
print("is post")
if form.is_valid():
print("is valid") # this never gets printed because of the 'this field is required' error
author = request.user
content = form.cleaned_data['description']
category = form.cleaned_data['categories']
picture = form.cleaned_data['picture']
privacy = form.cleaned_data['privacy']
p_post = PicturePost(author=author, description=content, categories=category, picture=picture,privacy=privacy )
p_post.save()
#redirect to last page
return redirect('home')
else:
l = []
for i in form.errors.keys():
l.append(form.errors[i])
return HttpResponse(l)
else:
post_type = 'picture'
form = PicturePostForm()
return render(request, 'create_post.html', {'form': form, 'post_type': post_type})
The corresponding model field
picture = models.ImageField(upload_to=f'profiles/{User}_gallery', max_length=255)
Fixed it by replacing form = PicturePostForm(request.POST) with form = PicturePostForm(request.POST, request.FILES)
I have tried to complete the code before, please following
views
#login_required()
def picture_post(request):
"""
Creates new picture post
"""
form = PicturePostForm(request.POST or None, request.FILES or None)
if request.method == "POST":
if form.is_valid():
# instance new object p_post (this best practice if using forms.ModelForm)
# commit=False (to save data on ram/memory device without database/hardrive)
p_post = form.save(commit=False)
# assign author attribute from thr current user session
p_post.author = request.user
# commit=True to move/save data from memory to harddrive
p_post.save() # p_post.save(commit=True)
return redirect('home')
else:
l = []
for i in form.errors.keys():
l.append(form.errors[i])
return HttpResponse(l)
post_type = 'picture'
return render(request, 'create_post.html', {'form': form, 'post_type': post_type})

"post" method condition not working in django form edit and save

After Clicking on a edit method in a form the data of the model gets loaded in the form view but when I click on the save button the value is not saved instead the page is again reloaded with the same values. Saving the New form in database via form works fine
views.py
def sessioncreate(request):
if request.method=="GET":
form=SessionForm();
return render(request,'app/sessions_form.html',{'form':form});
elif request.method=="POST":
form=SessionForm(request.POST);
form.save();
return HttpResponseRedirect('/sessions');
def SessionUpdate(request,pk):
post = get_object_or_404(Sessions, pk=pk)
if request.method == "post":
form = SessionForm(request.POST)
form.save()
return RedirectView('/sessions',pk=form.pk);
else:
form = SessionForm(instance=post)
return render(request,'app/sessions_form.html',{'form':form});
models.py
class Sessions(models.Model):
title=models.CharField(max_length=50)
abstract=models.CharField(max_length=2000)
track=models.ForeignKey(Track)
speaker=models.ForeignKey(Speaker)
status=models.CharField(max_length =1, choices=SESSION_STATUSES)
# returning name in site
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('sessions_detail', kwargs={'pk':self.pk})
class SessionForm(forms.ModelForm):
class Meta:
model=Sessions;
fields=['title','abstract','track','speaker'];
url.py
url(r'^sessions/$',views.SessionList.as_view(),name='sessions_list'),
url(r'^sessions/(?P<pk>[0-9]+)/$',views.SessionDetail.as_view() , name='sessions_details'),
url(r'^sessions/create/$',views.sessioncreate, name='sessions_create'),
url(r'^sessions/update/(?P<pk>[0-9]+)/$',views.SessionUpdate , name='sessions_update'),
url(r'^sessions/delete/(?P<pk>[0-9]+)/$',views.SessionDelete.as_view() , name='sessions_delete'),
session_form.html
{% extends 'layout.html' %}
{% block content %}
<form method="post">
{% csrf_token%}
{{form.as_table}}
<button type="submit">Save</button>
</form>
{% endblock %}
Methods are all caps. You should check if request.method == 'POST'.
Note also that you never check that your form is valid; you should do so by calling if form.is_valid() before the save.
This was my final views.py update file which worked...anything redundant i can remove from that ?
def SessionUpdate(request,pk):
form_class=SessionForm
post = get_object_or_404(Sessions, pk=pk)
form = SessionForm(request.POST)
if request.method == "POST":
if form.is_valid():
form = SessionForm(request.POST, instance=post)
form.save()
return HttpResponseRedirect('/sessions')
else:
form = SessionForm(instance=post)
return render(request,'app/sessions_form.html',{'form':form});

Django form fields not showing up

I am new to django and trying to show a form in an html file and I don't see the fields when I get to this particular page on my browser. Anybody has an idea why?
Here is the html file : In which I can see everything but the form showing up
add_device.html
{% extends 'layout/layout1.html' %}
{% block content %}
<form action = "userprofile/" method = "post">
{% csrf_token %}
{{ form }}
<input type = "submit" value = "Submit"/>
</form>
{% endblock %}
forms.py
from django import forms
from models import UserProfile
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('deviceNb',)
models.py
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User)
deviceNb = models.CharField(max_length = 100)
User.profile = property(lambda u : UserProfile.objects.get_or_create(user = u)[0])
views.py
def user_profile(request):
if request.method == 'POST':
#we want to populate the form with the original instance of the profile model and insert POST info on top of it
form = UserProfileForm(request.POST, instance=request.user.profile)
if form.is_valid:
form.save()
#to go back to check that the info has changed
return HttpResponseRedirect('/accounts/loggedin')
else:
#this is the preferred way to get a users info, it is stored that way
user = request.user
profile = user.profile
#if we have a user that has already selected info, it will pass in this info
form = UserProfileForm(instance=profile)
args = {}
args.update(csrf(request))
args['form'] = form
print(form)
return render_to_response('profile.html',args)
I am pretty sure my url file is ok, since I get to the right urls, my problem is really the form fields not showing up.
Thank you so much!!
You are not handling GET request in your view. Update code of the view as
def user_profile(request):
if request.method == 'POST':
# your existing code
# .....
else : #when its get request
form = UserProfileForm(instance=request.user.profile)
args = {}
args.update(csrf(request))
args['form'] = form
return render_to_response('profile.html',args)
This is a sample code, it can be improved.
The indentation of your view is incorrect. The else block belongs with the if request.method == 'POST' statement, and handles GET requests.
You also need to fix the indentation at the end of the method, so that you return a response for get and post requests. It's better to use render instead of the obsolete render_to_response. This simplifies your code, because you don't need to call args.update(csrf(request)) anymore.
from django.shortcuts import render
def user_profile(request):
if request.method == 'POST':
#we want to populate the form with the original instance of the profile model and insert POST info on top of it
form = UserProfileForm(request.POST, instance=request.user.profile)
if form.is_valid:
form.save()
#to go back to check that the info has changed
return HttpResponseRedirect('/accounts/loggedin')
else:
#this is the preferred way to get a users info, it is stored that way
user = request.user
profile = user.profile
#if we have a user that has already selected info, it will pass in this info
form = UserProfileForm(instance=profile)
args = {}
args['form'] = form
return render(request, 'profile.html', args)
You should handle GET request, too. Try this in your view:
def user_profile(request):
form = UserProfileForm()
if request.method == 'GET':
# handle GET request here
form = UserProfileForm(instance=request.user.profile)
elif request.method == 'POST':
#we want to populate the form with the original instance of the profile model and insert POST info on top of it
form = UserProfileForm(request.POST, instance=request.user.profile)
if form.is_valid:
form.save()
#to go back to check that the info has changed
return HttpResponseRedirect('/accounts/loggedin')
args = {}
args['form'] = form
return render_to_response('profile.html',args)
And in your profile.html, you can do something like this:
{{ form.as_p }}

Django view receives GET Request from form that should be sending POST

I have a view that is supposed to handle the submission of a form. The HTML form in the template is supposed to be sending a post however the view only ever receives a GET request.
View:
def eventSell(request, id):
event = Event.objects.get(pk = id)
if request.user.is_authenticated():
print request.user
if request.method == ['POST']:
print 'post'
form = ListingForm(request.POST)
if form.is_valid():
print 'form is valid'
user = request.user
price = request.POST['price']
t = Object(event = event, price = price, seller = user, date_listed = timezone.now())
t.save()
return HttpResponseRedirect(reverse('app:index'))
else:
print 'get'
form = ListingForm()
return render_to_response('app/list.html', {'form' : form, 'event' : event}, context_instance = RequestContext(request))
else:
return HttpResponseRedirect(reverse('allauth.accounts.views.login'))
Template:
<form action="" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
</form>
I'm really stumped here so any advice would be really appreciated. Thanks.
It is probably sending a POST however, you are not listening correctly.
if request.method == ['POST']:
should be
if request.method == 'POST':
Or just
if request.POST:
One more thing.
You can use the #login_required decorator instead of manually checking for authenticated users.