Use next parameter for login_required views - django

My method to redirect a url after login, work well but the code of the template is not very sexy, can I have yours please ?
my function in views.py
def connexion(request):
error = False
n=request.GET.get('n')
if request.method == "POST":
form = ConnexionForm(request.POST)
if form.is_valid():
username = form.cleaned_data["username"]
password = form.cleaned_data["password"]
user = authenticate(username=username, password=password)
if user:
login(request, user)
if request.GET.get('n'):
return redirect(request.GET['n'])
else:
return redirect(accueil)
else:
error = True
else:
form = ConnexionForm()
return render(request, 'blog/connect_user.html', locals())
my template:
<h1>Se connecter</h1>
{% if error %}
<p><strong>Utilisateur inconnu ou mauvais mot de passe.</strong></p>
{% endif %}
{%if n %}
<form method="post" action="{% url 'connexion' %}?n={{ n }}">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Se connecter" />
</form>
{% else %}
<form method="post" action="{% url 'connexion' %}">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Se connecter" />
</form>
{% endif %}
my decorator:
#login_required(redirect_field_name='n')

Why not just:
<input type="hidden" name="n" value="{{ n }}">
And in the view:
n = request.REQUEST.get('n', '')
Using request.REQUEST you can get n from either using POST or GET so you can still link to a URL like /login?n=/foo/bar. You can also do POST/REDIRECT/GET without problems.

Related

Update view not displaying data

I have a function-based view that does not load the data that was inputted. The view does not throw any error at all. It just presents the form as a blank one.
urls.py
path('edit/<slug>/', editPost, name='edit'),
views.py
#login_required
def editPost(request, slug):
if request.method == 'POST':
post = get_object_or_404(Post, slug=slug)
form = PostForm(request.POST or None, request.FILES or None, instance=post)
if form.is_valid():
post.author = request.user.username
post.updated = True
form.save()
return redirect('dashboard')
else:
form = PostForm(request.POST, request.FILES, instance=post)
return render(request, 'edit_post.html', {'form': form})
template
<form class="dropdown-item" action="{% url 'edit' slug=post.slug %}" method="post">{% csrf_token %}
<input class="btn btn-sm" type="submit" value="Edit">
render form in template, using {{ form.as_p }}
<form class="dropdown-item" action="{% url 'edit' slug=post.slug %}" method="post">
{% csrf_token %}
<!-- render form here -->
{{ form.as_p }}
<input class="btn btn-sm" type="submit" value="Edit">
</form>
or loop through form fields as
<form class="dropdown-item" action="{% url 'edit' slug=post.slug %}" method="post">
{% csrf_token %}
<!-- render form here -->
{% for field in form %}
{{ field.label }}
{{ field }}
{{ field.error }}
{% endfor %}
<input class="btn btn-sm" type="submit" value="Edit">
</form>
#login_required
def editPost(request, slug):
post = get_object_or_404(Post, slug=slug)
if request.method == 'POST':
form = PostForm(request.POST or None, request.FILES or None, instance=post)
if form.is_valid():
post.author = request.user.username
post.updated = True
form.save()
return redirect('dashboard')
else:
form = PostForm(instance=post)
return render(request, 'edit_post.html', {'form': form})
Probably you have to do something like that, there is not any reason to pass request.POST and request.FILES when you don't have POST action in the view. In that way you just have to pass the post object that have all the related info.
And also you have to render your form in the following way:
<form class="dropdown-item" action="{% url 'edit' slug=post.slug %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<!-- render form here -->
{{ form.as_p }}
<input class="btn btn-sm" type="submit" value="Edit">
</form>
Notice that enctype="multipart/form-data" is mandatory 'cause you are dealing with files in your form elsewhere it won't work properly.
Also checkout where you have to put your post = get_object_or_404(Post, slug=slug) line, 'cause in thay way you can pass the object to whatever action that is being performing (POST or GET).

django custom login view (login as guest)

i am making an ecommerce and i have a checkout view in that view i have three forms : a login form a guest login form and a billing address form so basically if a user is logged in normally or as guest i am displaying the billing address form in the template 'checkout.html' otherwise i display the login form and the guest login form but these two forms are handled in different views checkout_login and guest_checkout_login so my question is : is it safe to do so ?
this is the checkout template :
{% if not billing_profile %}
<form method="post" action="{% url 'login_page' %}"> {% csrf_token %}
<input type="hidden" name="next" value="{{ request.build_absolute_uri }}">
{{ form }}
<button type="submit" class="btn btn-default">Submit</button>
</form>
<form method="post" action="{% url 'guest_login_page' %}"> {% csrf_token %}
<input type="hidden" name="next" value="{{ request.build_absolute_uri }}">
{{ guest_form }}
<button type="submit" class="btn btn-default">Submit</button>
</form>
{% else %}
<h1>checkout</h1>
billing profile:{{billing_profile}} </br>
<form method="post" action=".">{% csrf_token %}
{{ adress_form }}
<button type="submit" class="btn btn-default">Submit</button>
</form>
{% endif %}
{% endblock %}
this is the chekout_login view:
def login_page(request):
form = LoginForm(request.POST or None)
next_ = request.POST.get('next')
if request.method == 'POST':
if form.is_valid():
username = form.cleaned_data.get("username")
password = form.cleaned_data.get("password")
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
if is_safe_url(next_, request.get_host()):
guest_email_id = request.session.get('guest_email_id')
if guest_email_id:
del request.session['guest_email_id']
return redirect(next_)
else:
return redirect("/")
else:
form = LoginForm()
return redirect("/")
if i am doing any mistake please tell me

Django form keeps complaining required field

The form submits but immediately says this field is required... although it was filled out. What am I doing wrong
In my view:
def fileupload(request):
if request.user.is_authenticated and request.user.is_staff:
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
handle_uploaded_file(request.FILES.getlist('file_field'))
return HttpResponseRedirect('/fileupload/')
else:
form = UploadFileForm()
return render(request, 'fileupload.j2.html', {'form': form})
return HttpResponseForbidden('<h1>403 Forbidden</h1>')
with this form:
class UploadFileForm(forms.Form):
kit_number = forms.CharField(label="Kit number", max_length=100, required=True, help_text='Required.')
file_field = forms.FileField(label='Upload kit result')
and template:
{% extends "menu.j2.html" %}
{% block content %}
{% if request.user.is_authenticated and request.user.is_staff %}
<h3>File upload</h3><br><br>
<form action="/fileupload/" method="post">
{% csrf_token %}
<div class="form-group">
<table>
{{ form.as_table() }}
</table>
</div>
<input id="button" class="btn" type="submit" value="Sent">
</form>
{% else %}
You are not authorized to see this page
{% endif %}
{% endblock %}
You forgot to set the form enctype.
<form action="/fileupload/" method="post" enctype="multipart/form-data">

Rewrite form with django forms

I want to rewrite the vote form of the django tutorial polls application. But I can't figure out how to make a radio list for all choices of a question:
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{% for choice in question.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br />
{% endfor %}
<input type="submit" value="Vote" />
</form>
After a lot of experimenting this was the solution:
#forms.py
class VoteForm(forms.ModelForm):
choice = forms.ModelChoiceField(queryset=None, widget=forms.RadioSelect)
class Meta:
model = Question
exclude = ('question_text', 'pub_date')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['choice'].error_messages = {
'required': 'No choice selected.',
'invalid_choice': 'Invalid choice selected.'
}
instance = getattr(self, 'instance', None)
if instance:
self.fields['choice'].queryset = instance.choice_set
#vote.html
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'polls/css/style.css' %}" />
<h2>{{ question.question_text }}</h2>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
{% if voted %}
<p><strong>Already voted on this question.</strong><p>
{% else %}
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{{ form.non_field_errors }}
<div class="fieldWrapper">
{{ form.choice.errors }}
{{ form.choice }}
</div>
<input type="submit" value="Vote" />
</form>
{% endif %}
<p>View results?</p>
#views.py
class VoteView(generic.UpdateView):
template_name = 'polls/vote.html'
model = Question
form_class = VoteForm
def get_queryset(self):
return Question.objects.filter(pub_date__lte=timezone.now()).exclude(choice__isnull=True)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# Check duplicate vote cookie
cookie = self.request.COOKIES.get(cookie_name)
if has_voted(cookie, self.object.id):
context['voted'] = True
return context
def get_success_url(self):
return reverse('polls:results', args=(self.object.id,))
def form_valid(self, form):
choice = form.cleaned_data['choice']
choice.votes = F('votes') + 1
choice.save()
redirect = super().form_valid(form)
# Set duplicate vote cookie.
cookie = self.request.COOKIES.get(cookie_name)
half_year = timedelta(weeks=26)
expires = datetime.utcnow() + half_year
if cookie and re.match(cookie_pattern, cookie):
redirect.set_cookie(cookie_name, "{}-{}".format(cookie, self.object.id), expires=expires)
else:
redirect.set_cookie(cookie_name, self.object.id, expires=expires)
return redirect

CSRF token missing or incorrect in signup

I'm trying to add a signup function to my website, this is what I have done so far...
added {% csrf_token %} in home.html
use render instead of rendor_to_response
added the middleware 'django.middleware.csrf.CsrfViewMiddleware'
home.html:
<div class="panel right">
<p>
<form action="/signup" method="post">
{% csrf_token %}
{% for field in user_form %}
{{ field }}
{% endfor %}
<input type="submit" value="Create Account">
</form>
</p>
</div>
Signup method in views.py
def signup(request):
user_form = UserCreateForm(data=request.POST)
if request.method == 'POST':
if user_form.is_valid():
username = user_form.clean_username()
password = user_form.clean_password2()
user_form.save()
user = authenticate(username=username, password=password)
login(request, user)
return render(request,'blog.html')
else:
return render(request,'index.html')
return redirect('/')
What's wrong with my code?