Passing Dropdown Value To URL in Django - python

I am rendering a dropdown which displays a list of integers. This is the only field in the form/view. Once that form is submitted, the integer selected should be passed to the URL of the next view which is rendered on submission of the previous form.
I am getting a 404 when I attempt this.
Here is what I am currently trying:
forms.py
#this is the dropdown field
class ManifestDropDown(forms.Form):
reference = forms.ModelChoiceField(queryset=Orders.objects.values_list('reference', flat=True).distinct(),
empty_label=None)
views.py
#this is the view where the dropdown is submitted
def manifest_references(request):
if request.method == 'POST':
form = ManifestDropDown(request.POST)
if form.is_valid():
reference_id = form.cleaned_data.get('reference')
form.save()
return render('manifest', reference_id=reference_id)
query_results = Orders.objects.all()
reference_list = ManifestDropDown()
context = {
'query_results': query_results,
'reference_list': reference_list,
}
return render(request, 'manifest_references.html', context)
#this is the view where the value should be displayed in the url
def manifest(request, reference_id):
form = CreateManifestForm(request.POST)
if request.method == "POST":
....
data = Manifests.objects.all().filter(reference__reference=reference_id)
form = CreateManifestForm(initial={
'reference': Orders.objects.get(reference=reference_id),
})
total_cases = Manifests.objects.filter(reference__reference=reference_id).aggregate(Sum('cases'))
context = {
'reference_id': reference_id,
'form': form,
'data': data,
'total_cases': total_cases['cases__sum'],
}
return render(request, 'manifest_readonly.html', context)
urls.py
#url which displays the manifest view above
url(r'^manifest/(?P<reference_id>\d+)/$', manifest, name='manifest'),
url(r'^references_manifests', manifest_references, name='references_manifests'),
manifest_references.html
<div class="container">
<br>
<br>
<br>
<form method="POST" action="references_manifests">
{% csrf_token %}
{{ reference_list }}
<button type="submit" class="btn btn-primary" name="button">Create Proforma</button>
</form>
</div>

To dynamically change the URL that you're actually submitting to, you would need to use JavaScript.
But an alternative is to submit back to the manifest_references view, then redirect from there to manifest. (Note, you should always be redirecting, not rendering, after a successful submission anyway. And no need to call form.save(), this isn't a modelform so there is nothing to save.)
def manifest_references(request):
if request.method == 'POST':
form = ManifestDropDown(request.POST)
if form.is_valid():
reference_id = form.cleaned_data.get('reference')
return redirect('manifest', reference_id=reference_id)

You can do two things:
Call the manifest view directly.
Redirect the user to the manifest page.
The first one should be done like this:
if form.is_valid():
reference_id = form.cleaned_data.get('reference')
form.save()
return manifest(request, reference_id)
The second one can be done like this:
if form.is_valid():
reference_id = form.cleaned_data.get('reference')
form.save()
return HttpResponseRedirect(reverse('manifest', reference_id = reference_id))
It doesn't really matter which one you do, although I would recomment redirecting the user to the correct page, because then a refresh will not resend the form the user has entered.

Related

Django Form Not Saving the Data

I've imported this from django.contrib.auth.forms import UserCreationForm
used csrf_token in the form but still when I hit submit the page reloads but doesn't save the data to database.
def signup(req):
if req.method == 'POST':
form = UserCreationForm(req.POST)
if form.is_valid():
form.save()
form = UserCreationForm()
reg_con={
'regform': form
}
return render(req, 'signup.html', reg_con)
form
<form action="." method="POST">
{% csrf_token %}
{{ regform.as_ul }}
<input type="submit" value="Sign Up">
</form>
This is normally because something is wrong with your form the problem is however that you each time construct a new form, and you thus can not see what went wrong. You should only create a new form in case it is a GET request, so:
def signup(req):
if req.method == 'POST':
form = UserCreationForm(req.POST)
if form.is_valid():
form.save()
else:
form = UserCreationForm()
reg_con={
'regform': form
}
return render(req, 'signup.html', reg_con)
Try removing the action attribute from your form tag. Also don't forget to redirect after calling form.save()

How to print post data on the same web page?

I am trying to print the POST data from django form on my webpage, right under my form. I am able to print it by HttpResponse on a different page, but I want it on the same page when the user presses submit button.
Views.py
from django.views.generic import TemplateView
from django.shortcuts import render
from django import forms
from django.http import HttpResponseRedirect, HttpResponse
from home.forms import HomeForm
def home(request):
def get(request):
form = HomeForm()
return render(request, 'home/home.html', {'form':form})
if request.method=='GET':
response=get(request)
return response
elif request.method == 'POST':
form = HomeForm(request.POST)
if form.is_valid():
text = HomeForm('post')
return HttpResponse('post')
else:
form = HomeForm()
return render(request, 'home/home.html', {'form':form})
Forms.py
from django import forms
class HomeForm(forms.Form):
post = forms.CharField( widget= forms.TextInput() )
Html template
<div class="container">
<form method='post'>
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="submit" class="btn btn-danger">
</form>
<h2>{{ text }}</h2>
</div>
I want the post field input to be displayed in the 'text' mentioned in the h2 tag of the webpage as soon as the user presses the submit button, and not on a separate page like HttpResponse does.
You have three options to get this thing done :
First is, you redirect the form on submit to the same page and pass the request.POST.DATA in context and then you can easily display it.
Like :
def home(request):
def get(request):
form = HomeForm()
return render(request, 'home/home.html', {'form':form})
if request.method=='GET':
response=get(request)
return response
elif request.method == 'POST':
form = HomeForm(request.POST)
if form.is_valid():
text = HomeForm('post')
# return HttpResponse('post')
context = {'text' : text, 'form' : form,}
return render(request, 'home/home.html', context)
else:
form = HomeForm()
return render(request, 'home/home.html', {'form':form})
Second Option is To display itself in the form the initial values from the Model :
form = HomeForm(initial = {'text' : modelsFile.Model.object}) # models.ModelName.text
Third Option is to use JavaScript and JQuery for realtime display of data.
That would be complex but good to do, you can search for how to display form data realtime in JS on google.
Thank you.

Django Form Submission button not working

So, I am following code4startup tutorial on how to create a similar to Ubereats app. Right now, I am trying to register a new Restaurant & restaurant owner to the database. I am using a form from Django to handle all the datafields.
Everything works fine until I hit the "sign-up" button. My code is SUPPOSED TO POST all the data from the form into the database, then automatically log-in the newly created restaurant owner into the restaurants page. HOWEVER, when i press the sign-up button, nothing happens and instead the sign-up page is reloaded.
How can i solve this issue? The tutorial I'm following is from 2017 i think so the django version the author uses is old.
Below are some snippets from my code:
SIGN-UP HTML (BUTTON ONLY, FORM WORKS OK):
<form method="POST" enctype="multipart/form-data" >
{% csrf_token %}
{{ user_form }}
{{ restaurant_form }}
<button type="submit">Sign Up</button>
VIEWS.py
def restaurant_home(request):
return render(request, 'restaurant/home.html', {})
def restaurant_sign_up(request):
user_form = UserForm()
restaurant_form = RestaurantForm()
#when submitting data:
if request == "POST":
user_form = UserForm(request.POST)
restaurant_form = RestaurantForm(request.POST, request.FILES)
if user_form.is_valid() and restaurant_form.is_valid():
new_user = User.objects.create_user(**user_form.cleaned_data)
new_restaurant = restaurant_form.save(commit=False)
new_restaurant.user = new_user
new_restaurant.save()
login(request, authenticate(
username = user.form.cleaned_data["username"],
password = user.form.cleaned_data["password"]
))
return redirect(restaurant_home)
return render(request, 'restaurant/sign_up.html', {
"user_form": user_form,
"restaurant_form": restaurant_form
})
I should be request.method in
if request.method == "POST":
Doc: HttpRequest.method
add the action attribute in the form tag to direct to the desired page
<form action=“/home“ method=“POST” ...>

Form is not saving user data into database Django

Python noob here trying to learn something very simple.
I'm trying to create a basic form that takes some personal information from a user and saves it into a sqlite3 table with the username of the user as the primary key.
My models.py looks like this:
class userinfo(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, primary_key= True,
on_delete=models.CASCADE)
name = models.CharField(max_length = 200, blank = True)
email = models.EmailField(max_length= 300, default = 'Null')
phone = models.CharField(max_length= 10, default = 'Null')
def __unicode__(self):
return self.user
forms.py:
class NewList(forms.ModelForm):
class Meta:
model = userinfo
exclude = {'user'}
views.py
def newlist(request):
if request.method == 'POST':
form = NewList(request.POST)
if form.is_valid():
Event = form.save(commit = False)
Event.save()
return redirect('/home')
else:
form = NewList()
return render(request, 'home/newlist.html', {'form': form})
html:
{% load static %}
<form action="/home/" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit">
</form>
urls.py too, but I don't know how that would help:
urlpatterns = [
url(r'^newlist/$', views.newlist, name='newlist')
]
So when I go to the url, I see the form. I can then fill the form, but when I submit the form, the data doesn't go into the database.
What am I doing wrong here?
Thanks in advance!
I think all you need to do is just save the form if it's valid, probably also add the userinfo as an instance of the form. You are also exluding the user from the form and need to assign it manually.
def newlist(request):
if request.user.is_authenticated():
user = request.user
if request.method == 'POST':
form = NewList(request.POST, instance=user.userinfo)
if form.is_valid():
form.save(commit=false)
form.user = user
form.save()
return redirect('/home')
else:
form = NewList(instance=user.userinfo) # add this if you want it to automatically fill the form with the old data if there is any.
return render(request, 'home/newlist.html', {'form': form})
The rest look like it should work.Except you need to send the post URL back to newlist:
{% load static %}
<form action="/newlist/" method="POST">
{% csrf_token %}
{{ form.as_p }}
</form>
If users are assigned at the creation of the model the first time, you don't need the user save, but since this is saving a users data you want to make sure they are logged in anyway:
def newlist(request):
if request.user.is_authenticated():
user = request.user
if request.method == 'POST':
form = NewList(request.POST, instance=user.userinfo)
if form.is_valid():
form.save()
return redirect('/home')
else:
form = NewList(instance=user.userinfo) # add this if you want it to automatically fill the form with the old data if there is any.
return render(request, 'home/newlist.html', {'form': form})
The instance is the model it is either going to save to, or copying data from. In the: form = NewList(request.POST, instance=user.userinfo) part, it is taking the POST data from the form, and linking that to the specific model entry of user.userinfo, however, it will only save to the database when you call form.save().
The user.userinfo is just so you can get the correct form to save to, as userinfo is a onetoone model to user. Thus making it possible to get it with user.userinfo.
The form = NewList(instance=user.userinfo) part is where it takes the currently logged in user's userinfo and copies into the form before it is rendered, so the old userinfo data will be prefilled into the form in the html. That being if it got the correct userinfo model.

Textarea not shown in Django form

I'm new to Django
In my homepage, I want to give 2 choices to users: to upload photos to a new album, or to an existing one.
The problem is one of the forms is initially not shown in the HTML,I can only see its submit button. But when I click on the submit button, then the form appears, along with the 'This field is required' warnings.
For this I have created 2 forms in forms.py
class AlbumForm(ModelForm):
class Meta:
model = Album
fields = ('title', 'description',)
class dropDownForm(forms.Form):
Albums = forms.ModelChoiceField(queryset=Album.objects.filter(user__id=1))
def __init__(self, user, *args, **kwargs):
super(dropDownForm, self).__init__(*args, **kwargs)
self.fields['Albums'].queryset = Album.objects.filter(user__id=user.id)
AlbumForm is for creating a new album, dropDownForm is for choosing from an existing one.
In views.py I have:
def upload_album(request):
if request.user.is_authenticated():
if request.user.albums.all() is not None:
albums = request.user.albums.all()
dropdownAlbum = request.POST.get('Albums')
if request.method == 'GET':
album = AlbumForm()
form = dropDownForm(request.user)
if ((request.method == 'POST') and ('ExistingAlbum' in request.POST)):
form = dropDownForm(request.user)
userID = request.user.id
curr = UserProfile.objects.filter(id=userID).first()
curr.currentAlbum = int(dropdownAlbum)
intAlbum = int(dropdownAlbum)
curr.save()
return HttpResponseRedirect('/upload-media')
if ((request.method == 'POST') and ('CreateNewAlbum' in request.POST)):
form2 = AlbumForm(request.POST)
if form2.is_valid():
album = form2.save(commit=False)
album.user = request.user
album = form2.save()
created_album_id = Album.objects.filter(title=album).first().id
userID = request.user.id
curr = UserProfile.objects.filter(id=userID).first()
curr.currentAlbum = created_album_id
curr.save()
request.user.albums.add(album)
return HttpResponseRedirect('/upload-media/')
return render(request, "base.html", locals())
and in HTML:
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" name="ExistingAlbum" value="Continue" href="/upload-media/">
</form>
</div>
<div>
<form method="POST">
{% csrf_token %}
{{ form2.as_p }}
<button type="submit" name="CreateNewAlbum" value="Create New Album">Create</button>
</form>
</div>
Any help is appreciated.
I've just looked up what locals actually is and that is a horrible way of constructing your context data (which is why I'm not surprised I haven't ever heard of it).
Your context data should be a dictionary made up of those values that you need in order for your template to render correctly. Therefore you should construct a dictionary that includes the elements that you need.
As a starting point that would be.
{
'form': AlbumForm(),
'form2': dropDownForm(request.user)
}
My guess is form2 does not appear.
The problem is: when you initially request the page it's a GET request, therefore only the following part is executed:
if request.method == 'GET':
album = AlbumForm()
form = dropDownForm(request.user)
return render(request, "base.html", locals())
Because other if branches require POST, which is a request verb used when submitting the data, which occurs when you press the Submit button.
When you call locals() the context is filled with album and form, but not form2, because it's not initialized in local scope in this case. You need to add form2 initialization to the above part, e.g.:
if request.method == 'GET':
form2 = AlbumForm()
form = dropDownForm(request.user)
...
return render(request, "base.html", locals())
P.S. Using locals() to fill a context is smart, but bad idea - it's insecure, it adds ALL the variables defined in the local scope to the context available in template.

Categories