I tried to upload the image several times, for some reason it just won't upload. I will explain in detail -
This table is on my django template.It will display data from a model called "WorkOut". This page has a form above this table for manual data input. Three fields in the table are going to be dynamic, that is where the issue is. In the picture you will see the "Start Time" field that says none. I want to fill this field with a button click. Idea is to click the button, that will trigger a views.py function and that will update the model and then display on this page. Once I do this successfully I will add the end time and do some calculations after.
I added a small form in the for loop to generate the button-
<td>
<form method="get">
<input type="submit" class="btn" value="Start Time" name="start_time">
</form>
</td>
Here is the views function that it is suppose to trigger-
def index_2(request):
if(request.GET.get('start_time')):
time=datetime.now().strftime('%H:%M:%S')
WorkOut.objects.update(start=time)
products=WorkOut.objects.all()
context={'products': products}
return render(request, 'myapp/index.html', context)
This page is the index and no separate url for the button click. I don't think I need one.
Here is the main index views:
def index(request):
form = WorkOutForm()
if request.method == 'POST':
form = WorkOutForm(request.POST)
if form.is_valid():
form.save()
products=WorkOut.objects.all()
context = {'form': form, 'products': products }
return render(request, 'myapp/index.html', context)
When I click the button it seems to get triggered but the function is not doing what it is suppose to do. My localhost url changes from 127.0.0.1:8000 to http://127.0.0.1:8000/?start_time=Start+Time. So something is happening but not the desired action.
Any idea what need to be changed?
Thank you for any input.
submit button value does not submit, so add a hidden field
index view:
def index(request):
form = WorkOutForm()
if request.method == 'POST':
form = WorkOutForm(request.POST)
if form.is_valid():
form.save()
elif request.GET.get('start_time'):
time=datetime.now().strftime('%H:%M:%S')
WorkOut.objects.update(start=time)
products=WorkOut.objects.all()
context = {'form': form, 'products': products }
return render(request, 'myapp/index.html', context)
form
<td>
<form method="get">
<input type="hidden" value="1" name="start_time">
<input type="submit" class="btn">
</form>
</td>
Related
I have multiple form fields, and multiple submit buttons on a same page. I want to detect by which form field a POST request is triggered.
I am using CBV and my post() method has this:
def post(self, request, **kwargs):
....
form1 = Form1(request.POST, instance=Model1.objects.filter(some_filtering...)
form2 = Form2(request.POST, instance=Model2.objects.filter(some_filtering...)
form3 = Form3(request.POST, instance=Model3.objects.filter(some_filtering...)
form4 = Form4(request.POST, instance=Model4.objects.filter(some_filtering...)
# this is the code I want to know
if POST request is triggered by form1...
# do something....
return super().post(request, **kwargs)
return super().post(request, **kwargs)
How can I detect which form triggered POST request?
I did it by using the input tag in HTML template instead of button tag for submitting the form
<form name="form-1" method="POST" action="{% url 'view_url_name'%}">
{% csrf_token %}
{{ form }}
<!--use input tag for submit button -->
<input class="btn mt-3 btn-primary" name="form-1-submit" value="Submit" type="submit"/>
</form>
Note: use the different name for each form submit input.
Now in your view, you can simply check for the name attribute of the button.
if 'form-1-submit' in request.POST:
form1 = Form1(request.POST, instance=Model1.objects.filter(some_filtering...)
...
# and so on
This implementation will also cover the scenario where you are
submitting the same form from different buttons to use that form data for different
purposes.
you can use an hidden input in your form like this
<input name="formId" value="1" type="hidden"/>
... <!-- in second form --!>
<input name="formId" value="2" type="hidden"/>
then in your view check which form submitted
if request.POST.get("formId") == "1":
form1 = Form1(request.POST, instance=Model1.objects.filter(some_filtering...)
elif request.POST.get("formId") == "2":
form1 = Form2(request.POST, instance=Model1.objects.filter(some_filtering...)
...
I am trying to create an 'add user' feature which will simply add the user you've selected from a dropdown as your connection. I am using ModelChoiceField from Django Forms so that I may get the existing users from my User model in the dropdown.
forms.py
from django import forms
from django.contrib.auth.models import User
class NetworkForm(forms.Form):
user_id = forms.ModelChoiceField(queryset=User.objects.all(), label='',
widget=forms.Select(attrs={'class': 'all_users'}))
views.py
#login_required
def index(request):
user_list = User.objects.exclude(username=request.user)
return render(request, 'chat/index.html', {'user_list': user_list})
For now I am just printing the form to see output
#login_required
def add_user(request):
form = NetworkForm()
if request.method == 'POST':
form = NetworkForm(request.POST)
if form.is_valid():
print form
return redirect(request.META['HTTP_REFERER'])
errors = form.errors or None
return render(request, 'chat/index.html', {
'form': form,
'errors': errors,
})
index.html
<div class="row">
<form action="{% url 'chat:add_user' %}" method="post">
{% csrf_token %}
{{ form.as_p }}
<button class="btn btn-warning" value="{{ user_id }}" style="float: left;">Submit</button>
</form>
</div>
urls.py
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^add_user/$', views.add_user, name='add_user'),]
The way it is being rendered currently is: I have my main index page where I don't see any dropdown, i.e.,
When I click on the submit button, it moves me to index/add_user, where I get a dropdown with user (with a warning "this field is required) and a submit button again.
Finally, when I choose a user in this new page and hit submit, finally the form is printed, which I want ultimately.
What I would want it, have the complete form with dropdown in the index page itself and remain there when I submit the form. I will then hook that to show user the users they have added beneath that form itself ('print' is just for debugging purpose - not a good way I've heard though).
I understand the post request will have to go to add_user page and I can redirect back from that. I have tried various alternatives for the past 6 hours, nothing works yet. Apologies for a long one, giving out information as much as possible. Thanks very much guys. You are awesome.
Edit
Have been now rendering the form in index page (suggestion from #fazil-zaid ), but the issue remains as in only 'submit' button appears on index initially, unless when I hit submit after which the dropdown and submit appears. Again, on clicking the second time, the form is submitted.
Edit-2
I am thinking that:
<form action="{% url 'chat:index' %}" method="post">{% csrf_token %}
{{ form.as_p }}
<button class="btn btn-warning" value="{{ user_id }}" style="float: left;">Submit</button>
</form>
this might be where the problem is, as per current logic unless user takes form's action, i.e., clicks the button {{ form.as_p }} will not appear. Then I tried:
{{ form.as_p }}
<form action="{% url 'chat:index' %}" method="post">{% csrf_token %}
<button class="btn btn-warning" value="{{ user_id }}" style="float: left;">Submit</button>
</form>
Doesn't work still. POST request doesn't send any data (understandably so).
If you want the form to be in the index page, then you could include it in the index view itself.
def index(request):
if request.method == 'POST':
form = NetworkForm(request.POST)
if form.is_valid():
#do what you wanna do
#with the form data.
else:
form = NetworkForm()
render(request, 'chat/index.html', { 'form': form})
In the template,
<div class="row">
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<button class="btn btn-warning" value="{{ user_id }}" style="float: left;">Submit</button>
</form>
</div>
You are not rendering another template, but the same 'index.html'. Then, multiple view for that is just redundant. Index page could contain the form and render itself. From what I understand, there's no need of redirections.
There's no need of add_user view if you're showing the form in the index page itself.
For your issue, try changing the "class" attribute of the form fields, maybe something like this,
class NetworkForm(forms.Form):
user_id = forms.ModelChoiceField(queryset=User.objects.all(), widget=forms.Select(attrs={'class': 'form-control'}))
Solution:
When the page is called in the first instance using GET, the form is not valid as it seeks a POST method. Hence, all the method need to be changed to POST in the view, i.e.,
#login_required
def index(request):
user_list = User.objects.exclude(username=request.user)
form = NetworkForm()
if request.method == 'POST':
form = NetworkForm(request.POST)
if form.is_valid():
print form.data
return redirect(request.META['HTTP_REFERER'])
return render(request, 'chat/index.html', {
'user_list': user_list,
'form': form,
})
Earlier, index was using a GET to render data to index page, and using a POST to use the form. Now, everything works fine.
Special shout-out to #fazil-zaid for the heads-up since you mentioned to include everything in the index view itself, rather than making a separate view for form. Your code pointed that out in a way in addition to Stack here.
I have the following view
def edit_booking(request, pk=None):
if not request.user.is_authenticated:
raise Http404
agent = Agent.objects.get(user=request.user)
booking = get_object_or_404(Booking, pk=pk)
form = BookingForm(request.POST or None, instance=booking)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
return HttpResponseRedirect(instance.get_absolute_url())
elif form.errors:
messages.error(request,"There was a problem, please try again")
context = {
"form": form,
}
return render(request,'booking_form.html', context)
I use the following urls.py
urlpatterns = [
url(r'^booking/create', create_booking, name="create-booking"),
url(r'^booking/$', booking_list, name="booking-list"),
url(r'^booking/(?P<pk>\d+)/$', booking_detail, name="booking-detail"),
url(r'^booking/(?P<pk>\d+)/edit', edit_booking, name="edit-booking"),
]
For some reason when I try to submit the form after editing some booking (e.g. http://127.0.0.1:8000/booking/24/edit) I am automatically redirected to (http://127.0.0.1:8000/booking/24/).
As far as I can tell django is not processing any further code in the view. I tried to figure out with simple print("something") to see where in the code it ends up but it just goes to the url right away as soon as I submit from the template. For completeness sake this is the template:
{% extends 'base.html' %}
<div class="col-sm-6 col-sm-offset 3">
{% block content %}
<form method="POST" action=".">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Save"/>
</form>
{% endblock %}
</div>
".", which you used as the action of the form, is interpreted by browsers as "the base of the current path directory". Since you have not used a trailing slash in your /edit URL, the browser submits the form to the nearest base, ie /booking/24.
You should always use a trailing slash:
url(r'^booking/create/$', create_booking, name="create-booking"),
url(r'^booking/$', booking_list, name="booking-list"),
url(r'^booking/(?P<pk>\d+)/$', booking_detail, name="booking-detail"),
url(r'^booking/(?P<pk>\d+)/edit/$', edit_booking, name="edit-booking"),
You need to check for the request method otherwise it will redirect on initial form rendering because django uses the same view for initial rendering and submitting the form.
if request.method == 'POST':
if form.is_valid():
instance = form.save(commit=False)
instance.save()
return HttpResponseRedirect(instance.get_absolute_url())
elif form.errors:
messages.error(request,"There was a problem, please try again")
else:
context = {
"form": form,
}
return render(request,'booking_form.html', context)
Who can help me with the following challenge?
I have a registration template where users can sign up. They are then redirected to an url with a payment button and activated when a successful payment is made. In the HTML template I store the username in a custom field within the payment button which is used to later activate the account. Now since the user is not activated/logged in yet, I can't call the user object yet like {{user.username}}. So I want to try sessions to solve this and capture the username during registration to retrieve this session variable and put it in my custom field on a different page. But how? I tried using request.session but I’m not sure where to fit this the files below and then how to call this variable in the html template.
Any advise or help is greatly appreciated!
Here is my regbackend.py
class MyRegistrationView(RegistrationView):
form_class = UserProfileRegistrationForm
def register(self, form_class):
user_package.username = form_class.cleaned_data['username']
And here my forms.py
class SignUpForm(forms.ModelForm):
class Meta:
model = SignUp
fields = ['username', 'email']
Here my registration.html
<form method="post" action=".">
{% csrf_token %}
{{ form.username|as_crispy_field }}
<input class="btn btn-success" type="submit" value="{% trans 'Submit' %}" /></form>
And finally my HTML Template for after registration with the payment button and custom field.
<form action="some-url" method="post" target="_top">
<input type="hidden" name="custom" value="{{ session.username? }}">
</form>
Im using Django 1.9x and Django-registration-redux
This is how I keep the session to use it on another view.
On your registration form :
def registration(request):
initial={'username': request.session.get('username', None)}
form = RegistrationForm(request.POST or None, initial=initial)
if request.method == 'POST':
if form.is_valid():
request.session['username'] = form.cleaned_data['username']
return HttpResponseRedirect(reverse('your_checkout_view'))
return render(request, 'registration.html', {'form': form})
Once the username field is completed and the form submited it goes to the second view in which you can take the username that is stored in your session.
Just like this :
def your_checkout_view(request):
username = request.session['username']
...
From there you can take the stored username and do what you have to do.
I face a problem which I can't find a solution for. I have a button in navbar which is available on all pages and it is a button responsible for creating some content.
View that links with button:
def createadv(request):
uw = getuw(request.user.username)
if request.method =='POST':
form = AdverForm(request.POST, request.FILES)
if form.is_valid():
form.instance.user = request.user
form.save()
return HttpResponseRedirect('/', {'username': request.user.username, 'uw': uw})
args = {}
args.update(csrf(request))
args['username'] = request.user.username
args['form'] = AdverForm()
args['uw'] = uw
return render_to_response('createadv.html', args)
If you can see now I always redirect to main page '/' after creating content but I want to go back to the page with which I launched the creation of content.
You can add a next field to your form, and set it to request.path. After you processed your form you can redirect to the value of this path.
template.html
<form method="POST">
{% csrf_token %}
{{ form }}
<input type="hidden" name="next" value="{{ request.path }}">
<button type="submit">Let's Go</button>
</form>
views.py
next = request.POST.get('next', '/')
return HttpResponseRedirect(next)
This is roughly what django.contrib.auth does for the login form if I remember well.
If you pass through an intermediate page, you can pass the 'next' value via the querystring:
some_page.html
Go to my form!
template.html
<form method="POST">
{% csrf_token %}
{{ form }}
<input type="hidden" name="next" value="{{ request.GET.next }}">
<button type="submit">Let's Go</button>
</form>
You can use the HTTP_REFERER value:
return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))
Note that this will not work if the client disabled sending referrer information (for example, using a private/incognito browser Window). In such a case it will redirect to /.
You can use this
return redirect(request.META.get('HTTP_REFERER'))
Make sure to import this
from django.shortcuts import redirect
My favorite way to do that is giving the request.path as GET parameter to the form.
It will pass it when posting until you redirect.
In Class-Based-Views (FormView, UpdateView, DeleteView or CreateView) you can directly use it as success_url.
Somewhere i read that it's bad practise to mix GET and POST but the simplicity of this makes it to an exception for me.
Example urls.py:
urlpatterns = [
path('', HomeView.as_view(), name='home'),
path('user/update/', UserUpdateView.as_view(), name='user_update'),
]
Link to the form inside of the template:
Update User
Class-Based-View:
class UserUpdateView(UpdateView):
...
def get_success_url(self):
return self.request.GET.get('next', reverse('home'))
In your function based view you can use it as follows:
def createadv(request):
uw = getuw(request.user.username)
if request.method =='POST':
form = AdverForm(request.POST, request.FILES)
if form.is_valid():
form.instance.user = request.user
form.save()
next = request.GET.get('next', reverse('home'))
return HttpResponseRedirect(next)
args = {}
args.update(csrf(request))
args['username'] = request.user.username
args['form'] = AdverForm()
args['uw'] = uw
return render_to_response('createadv.html', args)
you could do this easily with a simple one-liner JS
<button onclick="history.back()">Go Back</button>
This will take you back to the previous page of your history list.
If you don't have a history
https://www.w3schools.com/jsref/met_his_back.asp
Use HTTP_REFERER value:
for use in func return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))
for use in template Go Back
In case this helps someone I got this to work in class based UpdateView
template
<form class="form" method="POST">
{% csrf_token %}
<!-- hidden form field -->
<input type="hidden" id="previous_page" name="previous_page"
value="/previous/page/url">
<!-- any other form fields -->
{{ form.name|as_crispy_field }}
{{ form.address|as_crispy_field }}
<!-- form submit button -->
<button class="btn btn-primary" type="submit" id="submit">Submit</button>
</form>
<!-- JS to insert previous page url in hidden input field -->
<script>
prev = document.getElementById("previous_page");
prev.value = document.referrer;
</script>
views.py
class ArticleUpdateView(generic.UpdateView):
model = Article
form_class = ArticleForm
template_name = 'repo/article_form.html'
def form_valid(self, form):
form.instance.author = self.request.user
# if form is valid get url of previous page from hidden input field
# and assign to success url
self.success_url = self.request.POST.get('previous_page')
return super().form_valid(form)
The view now redirects you back to the page where you had clicked the "Update/Edit" button. Any URL query parameters are also preserved.