I want to create a form in my navigation bar. I am using a context processor for that.
I created themeChoice field in my UserProfile model. What I want to is when user click submit button, form will be save. I tried something but it did not work, my view prints nothing. How can I do that?
Note: my context processor is working.
views.py
def approval_context_processor(request):
...
if request.method == 'POST':
form_theme = UserThemeChoiceform(request.POST)
if form_theme.is_valid():
user_who = request.POST.get('user_who', None)
user = UserProfile.objects.get(id=user_who)
print(user_who)
form_theme.save()
return redirect('home')
context= {
...
'form': form_theme,
}
return context
navigation.html
<form method="POST" id="theme" action="#">
{% csrf_token %}
<input type="hidden" name="user_who" value="{{ request.user }}" >
<button type="submit" class="btn btn-success">Send</button>
</form>
Related
I have a page with two forms. When I click on the button Update Profile on the left Form it also send the POST request to the the second form which is not what I want. I don't want them to interact together. How can I do that?
views.py
#login_required(login_url='signin')
def dashboard(request):
global user_id
data = Account.objects.filter(user=request.user)
profile_data = Profile.objects.get(user=request.user)
profile_form = ProfileForm(request.POST or None, instance=profile_data)
addaccount_form = AddAccountForm(request.POST or None)
# Update Profile Settings
if profile_form.is_valid():
print("worked")
profile_form.save()
if request.method == "POST":
if addaccount_form.is_valid():
# save account to DataBase
return HttpResponseRedirect("http://127.0.0.1:7000/dashboard/")
context = {
'data': data,
'profile_form': profile_form,
'addaccount_form': addaccount_form,
}
return render(request, "main/dashboard.html", context)
dashboard.html
<form action="" method="POST">
{% csrf_token %}
{{profile_form}}
<button type="submit" class="updatebut">Update Profile</button>
</form>
<form action="" method="POST">
{% csrf_token %}
{{addaccount_form}}
<button type="submit" class="addbut">Add Account</button>
</form>
You can check which form in your request
if 'profile_form' in request.POST:
profile_form = ProfileForm(request.POST or None, instance=profile_data)
if profile_form.is_valid():
print("worked")
profile_form.save()
elif 'addaccount_form' in request.POST:
addaccount_form = AddAccountForm(request.POST or None)
if addaccount_form.is_valid():
# save account to DataBase
return HttpResponseRedirect("http://127.0.0.1:7000/dashboard/")
You can add a name to each one of your submit buttons (ex. name="addaccount" and name="updateprofile")
And in your view, add the following:
if 'addaccount' in request.POST:
---do the addacount
elif 'updateprofile' in request.POST:
---do the profile update
Quick and dirty!
I want to use ready Django LoginView, but in the same time I have to use my own view for registration in same HTML template. If in urls.py file I will connect 2 views than i will connect only first. So my question is that how can use LoginView in my own view and use 2 forms with jinja?
here is my views.py file and html ;)
def index(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
formlog = auth_views.LoginView.as_view(template_name='main/index.html')
if 'signup' in request.POST:
if form.is_valid():
form.supervalid()
form.save()
username = form.cleaned_data.get('username')
messages.success(request, f'Dear {username} you have been created a new accound!')
return redirect('main')
elif 'login' in request.POST:
if formlog.is_valid():
formlog.save()
username = form.cleaned_data.get('username')
messages.success(request, f'Your account has been created! You are now able to log in')
return redirect('main')
else:
form = UserRegisterForm()
formlog = auth_views.LoginView.as_view(template_name='main/index.html')
return render(request, 'main/index.html', {'form': form, 'formlog': formlog})
# this code is not working , but not returning any errors
HTML
{% if not user.is_authenticated %}
<!-- Login -->
<div class="container">
<div class="log-1">
<div class="log-0">
<p class="logtitle">BareTalk</p>
<form method="POST" name="login">
{% csrf_token %}
{{ formlog|crispy }}
<button class="log-button first" type="submit">Login</button>
</form>
<button class="log-button second"
onclick="modalwindowops.open();" id="signup">Sign Up</button>
</div>
</div>
</div>
<!-- Signup -->
<div class="modal-overlay">
<div class="modal-window">
<span class="close-modal" onclick="modalwindowops.close();">×</span>
<form method="POST" name="signup">
<p>Sign Up</p>
{% csrf_token %}
{{ form|crispy }}
<button type="submit">Sign Up</button>
</form>
</div>
</div>
{% else %}
<h1>Welcome back Amigo!</h1>
{% endif %}
Neither if 'signup' in request.POST: nor elif 'login' in request.POST: is triggered in your index() view because your HTML forms do not actually contain those inputs. Note that the name attribute is deprecated for the <form> element.
Instead you can add a hidden <input> inside your forms, like this:
<form method="POST">
{% csrf_token %}
{{ formlog|crispy }}
<input type="hidden" name="login" value="true" />
<button class="log-button first" type="submit">Login</button>
</form>
Also,
formlog = auth_views.LoginView.as_view(template_name='main/index.html')
saves a view to formlog, not a form, so calling formlog.is_valid() will cause an error.
Instead of
elif 'login' in request.POST:
if formlog.is_valid():
formlog.save()
username = form.cleaned_data.get('username')
messages.success(request, f'Your account has been created! You are now able to log in')
return redirect('main')
you probably will only need to do
elif 'login' in request.POST:
log_view = auth_views.LoginView.as_view(template_name='main/index.html')
log_view(request)
Calling is_valid(), save(), and doing the redirect is all done by LoginView already. If you want to still do the custom message.success() you will have to override one or more of the LoginView methods, but that is another topic.
Update:
You also need to change this line in the view: formlog = auth_views.LoginView.as_view(template_name='main/index.html') (before return render...) to:
formlog = AuthenticationForm(request)
Take this line outside of the else block.
Also add the import for the form at the top of your views.py:
from django.contrib.auth.forms import AuthenticationForm
This change is required because the template needs the form object (which is AuthenticationForm for LoginView by default) instead of the view object. The updated view function will look like:
from django.contrib.auth.forms import AuthenticationForm
def index(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
if 'signup' in request.POST:
if form.is_valid():
form.supervalid()
form.save()
username = form.cleaned_data.get('username')
messages.success(request, f'Dear {username} you have been created a new accound!')
return redirect('main')
elif 'login' in request.POST:
log_view = auth_views.LoginView.as_view(template_name='main/index.html')
log_view(request)
else:
form = UserRegisterForm()
formlog = AuthenticationForm(request)
return render(request, 'main/index.html', {'form': form, 'formlog': formlog})
Note that this can be improved by providing feedback when the login credentials are invalid. As it is, this updated code only reloads a blank login form if the provided credentials don't work.
I have a table with atrributes, and I'm displaying each attribute as a checkbox in html view. I want to show them in different pages, but I don't want to make different functions for each category. Is there an efficient way to do so? Here is what I tried so far.
def questions(request):
# start session page for the user to test
questions = Attribute.objects.all()
realistic = Attribute.objects.filter(holland_code=1)
investigative = Attribute.objects.filter(holland_code=2)
artistic = Attribute.objects.filter(holland_code=3)
social = Attribute.objects.filter(holland_code=4)
enterprising = Attribute.objects.filter(holland_code=5)
conventional = Attribute.objects.filter(holland_code=6)
left = [realistic, investigative, artistic, social, enterprising, conventional]
for attribute in left:
# get all the values form the form submitted
if request.method == "POST":
# THIS WILL GET ALL THE RECOMMENDAITONS
rAttributes = request.POST.getlist('realistic')
print(rAttributes)
return render(request, "main/questions.html", {"questions": attribute})
context = {
"questions": realistic,
}
return render(request, 'main/questions.html', context)
This is my html template to display the checkboxes
<form action="" method="POST">
{% csrf_token %}
<div class="form-check">
{% for question in realistic %}
<input type="checkbox" class="form-check-input" id="exampleCheck1" name="realistics" value="{{ question.attribute_name }}">
<label class="form-check-label" for="exampleCheck1">{{ question.attribute_name }}</label>
<br>
{% endfor %}
</div>
<input type="submit" class="btn btn-danger" value="Next">
</form>
Just add the form to the base template and extend that template so it'll be available everywhere.
or you could create a class based view and add a post request
class InsterViewNameHere(View):
def post(request, self, id=None, *args, **kwargs):
#form logic and context here
context = {}
return render(request, 'template.html', context)
To not have to repeat the same post function for every view or class-based-view, you could create a Mixin view
class ObjectnameMixin(object):
model = ClassModel
form = formname
def post_form(self):
return form
I'm learning Django and have some troubles with forms. I try to create a simple form where I type a name and show it on another page. But is_valid() always returns false. Please, help me to find my error
forms.py
from django import forms
class OrderForm(forms.Form):
user=forms.CharField(max_length=100)
views.py
def order(request):
return render(request, 'myapp/order.html', {})
def contact(request):
username='not logged'
if request.method == 'POST' :
form=OrderForm(request.POST)
if form.is_valid():
username=form.cleaned_data['username']
else:
username='not worked'
else:
form=OrderForm()
return render(request, 'myapp/contacts.html', {'username':username})
order.html
<form name = "form" action = "{% url 'contact' %}" method = "POST" >
{% csrf_token %}
<input type="text" name="username" placeholder="Name">
<button type="submit">Login</button>
</form>
contacts.html
You are : <strong>{{ username }}</strong>
Your form control has the name username in HTML, while your form's field is named user in Django. Thus, nothing is set in the form field.
Normally you'd put the form into the context and then render it either as {{ form }} or the like, or render each field, rather than build your own form controls. The docs show how: https://docs.djangoproject.com/en/1.10/topics/forms/#working-with-form-templates
views.py
from forms import OrderForm
def order(request):
form = OrderForm()
return render(request, 'myapp/order.html', {"form" : form})
order.html
<form name = "form" action = "{% url 'contact' %}" method = "POST" >
{% csrf_token %}
{{form.as_p}}
<button type="submit">Login</button>
</form>
At the time of rendering template {{form.as_p}} looks like
<p><label for="id_username">Username:</label>
<input id="id_username" type="text" name="username" maxlength="100" required /></p>
I'm coding a login. When I programmed the form by hand I got it working.
The code below works:
views.py
def login_view(request):
if request.method == 'GET':
return render(request, 'app/login.htm')
if request.method == 'POST':
username = request.POST.get('username', '')
password = request.POST.get('password', '')
user = auth.authenticate(username=username, password=password)
if user is None:
return HttpResponseRedirect(reverse('error'))
if not user.is_active:
return HttpResponseRedirect(reverse('error'))
# Correct password, and the user is marked "active"
auth.login(request, user)
# Redirect to a success page.
return HttpResponseRedirect(reverse('home'))
template:
<form method="post" action="{% url 'login' %}">
{% csrf_token %}
<p><label for="id_username">Username:</label> <input id="id_username" type="text" name="username" maxlength="30" /></p>
<p><label for="id_password">Password:</label> <input type="password" name="password" id="id_password" /></p>
<input type="submit" value="Log in" />
<input type="hidden" name="next" value="" />
</form>
Great! But now I want to do the same thing using Django's forms.
The code below is not working because I get is_valid() == False, always.
views.py:
def login_view(request):
if request.method == 'POST':
form = AuthenticationForm(request.POST)
print form.is_valid(), form.errors, type(form.errors)
if form.is_valid():
## some code....
return HttpResponseRedirect(reverse('home'))
else:
return HttpResponseRedirect(reverse('error'))
else:
form = AuthenticationForm()
return render(request, 'app/login.htm', {'form':form})
template:
<form action="{% url 'login' %}" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
There are a bunch of people on stackoverflow complaining that they get is_valid always false. I have read all those posts, and as far as I can tell I'm not making any of those mistakes. I found a new mistake to make :-)
EDIT: I added a print in the code. The output when opening the login view and submitting is
[27/Dec/2013 14:01:35] "GET /app/login/ HTTP/1.1" 200 910
False <class 'django.forms.util.ErrorDict'>
[27/Dec/2013 14:01:38] "POST /app/login/ HTTP/1.1" 200 910
and so is_valid() is False, but form.errors is empty.
It turns out that Maxime was right after all (sorry) - you do need the data parameter:
form = AuthenticationForm(data=request.POST)
The reason for that, though, is that AuthenticationForm overwrites the signature of __init__ to expect the request as the first positional parameter. If you explicitly supply data as a kwarg, it will work.
(You should still leave out the else clause that redirects away on error, though: it's best practice to let the form re-render itself with errors in that case.)
Check out form.errors which will help you find out why.
If situation arises, that you don't have an option (I was trying to work with bootstrap modals and it was just not working), I had to do this, or else the modal would always trigger even if the form had not issues (and the is_valid is always False by default)
What I needed:
Show modal when I click a button
if errors, show on the same page, the modal, with the error.
In the modal template:
{% if not brand_form.is_valid and brand_form.errors %}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
<script type="text/javascript">
$(window).on('load', (function() {
$('#brandAddModal').modal('show');
}));
</script>
{{ brand_form.non_field_errors }}
{% endif %}
In the view:
def add_brand_form(request):
form = BrandForm()
if request.method == 'POST':
form = BrandForm(data=request.POST)
if form.is_valid():
return HttpResponseRedirect('/home')
else:
return render(request, template_name='home.html', context={'brand_form':form})
return render(request, template_name='modal_add_brand.html', context={'brand_form':form})