I am making a decorator to insert verification code into a template. The scenario is the following :
#insert_verification
def my_view(request):
# View code here...
return render(request, 'myapp/index.html', {"foo": "bar"},
content_type="application/xhtml+xml")
def insert_verification(func):
def wrapped(request):
res = func(request)
if type(res) == HttpResponse:
# add a verification code to the response
# just something like this : res.add({"verification": 'xxxxx'})
# and varification can fill in the template
return res
return wrapped
I use the following template:
{% block main %}
<fieldset>
<legend>{{ title }}</legend>
<form method="post"{% if form.is_multipart %} enctype="multipart/form-data"{% endif %}>
{% fields_for form %}
<input type="hidden" value="{{varification}}" >
<div class="form-actions">
<input class="btn btn-primary btn-large" type="submit" value="{{ title }}">
</div>
</form>
</fieldset>
{% endblock %}
It seems I should render a template twice with different dictionary. But I don't know how to do that.
I think the better approach will be to implement your context processor to add verification context variable to the template contexts.
For example:
verification_context_processor.py
def add_verification(request):
#get verification code
ctx = {'verification': 'xxxxx'}
#you can also check what path it is like
#if request.path.contains('/someparticularurl/'):
# add verification
return ctx
In settings.py, update
import django.conf.global_settings as DEFAULT_SETTINGS
TEMPLATE_CONTEXT_PROCESSORS = DEFAULT_SETTINGS.TEMPLATE_CONTEXT_PROCESSORS + (
'custom_context_processors.add_verification',
)
You view should use RequestContext while rendering the response.
def my_view(request):
# View code here...
return render_to_response(request, 'myapp/index.html', {"foo": "bar"},
context_instance=RequestContext(request)
)
Related
I'm trying to clone the Instagram web page using Django(version-3.1).
My Django project has an app called 'post'.
One of its template I have a form which is posting a comment to a post. The form post request should call the path('add_comment/',views.add_comment,name='add_comment'), but It's calling path('<slug:slug>/',views.post_details,name='post_details'), instead. And raising DoesNotExist at /post/add_comment error. I added print() statement at the beginning of both add_comment() and post_details() methods to find out which is running when the request is made. I have no idea what I have done wrong.
The project GitHub link - https://github.com/mirasel/Instagram_Clone
the post_details.html template is -
{% extends 'base.html' %}
{% load static %}
{% block title %} post {% endblock %}
{% block profilephoto %} {{ propic.url }} {% endblock %}
{% block body %}
<div>
<div>
<img src="{{post.image.url}}" alt="post" height="250px" width="250px">
</div>
<div>
<a href="{% url 'instagram:profile' post.uploader %}">
<img src="{{uploader.profile_pic.url}}" alt="{{uploader}}" style="border-radius: 50%;" height="24px" width="24px">
{{ post.uploader }}
</a><br>
<p>{{ post.date_published.date }}</p>
</div>
<div>
<p>{{ post.caption }}</p>
</div>
<div>
<form action="{% url 'post:add_comment' %}" id="comment_form" method="POST">
{% csrf_token %}
<textarea name="comment" id="comment" cols="30" rows="1" placeholder="Write a comment..."></textarea>
<input type="hidden" name="slug" id="slug" value="{{post.slug}}">
<!-- <input type="submit" style="display: none;" name="submit"> -->
</form>
<script>
$(function(){
$("#comment").keypress(function (e) {
if(e.which == 13 && !e.shiftKey) {
$(this).closest("form").submit();
e.preventDefault();
}
});
});
</script>
{% endblock %}
the views.py -
from django.shortcuts import render,redirect
from instagram.views import get_nav_propic,get_profile_details
from .models import UserPost,PostComment,PostLike
from django.http import JsonResponse
def get_post_likes(post):
likes = PostLike.objects.filter(post=post)
total_likes = len(likes)
likers = []
for l in likes:
likers.append(get_profile_details(l.liker))
return {'likers':likers,'total_likes':total_likes}
def get_post_comments(post):
comments = PostComment.objects.filter(post=post)
total_comments = len(comments)
commenter = []
comment = []
for c in comments:
commenter.append(get_profile_details(c.commenter))
comment.append(c.comment)
postcomment = zip(commenter,comment)
return {'post_comment':postcomment,'total_comments':total_comments}
def upload_post(request):
if request.method == 'POST':
image = request.FILES['post_img']
caption = request.POST['caption']
uploader = request.user
UserPost.objects.create(uploader=uploader,image=image,caption=caption)
return redirect('instagram:feed')
else:
context = {
'propic' : get_nav_propic(request.user)
}
return render(request,'post/upload_post.html',context)
def post_details(request,slug):
print('I am here in post details')
post = UserPost.objects.get(slug=slug)
context = {
'propic' : get_nav_propic(request.user),
'post' : post,
'uploader' : get_profile_details(post.uploader),
'LIKES' : get_post_likes(post),
'COMMENTS' : get_post_comments(post),
}
return render(request,'post/post_details.html',context)
def add_comment(request):
print('I am here in add comment')
if request.method == 'POST':
post_slug = request.POST.get('slug')
post = UserPost.objects.get(slug=post_slug)
user = request.user
comment = request.POST.get('comment')
PostComment.objects.create(post=post,commenter=user,comment=comment)
return redirect('post:post_details',slug=post_slug)
the urls.py -
from django.urls import path
from . import views
app_name='post'
urlpatterns = [
path('upload_post/',views.upload_post,name='upload_post'),
path('<slug:slug>/',views.post_details,name='post_details'),
path('add_comment/',views.add_comment,name='add_comment'),
]
The error - Error page
Solved
I had to make the URL path of add_comment as following-
#previous one
path('add_comment/',views.add_comment,name='add_comment'),
#modified one
path('comment/add_comment/',views.add_comment,name='add_comment'),
This is because the pattern for the slug URL and add comment URL were similar.
Because Django will process the urlpatterns sequentially, from docs:
Django runs through each URL pattern, in order, and stops at the first
one that matches the requested URL, matching against path_info.
And '/add_comment' is a valid slug <slug:slug>, so post_details will be called.
So you should keep the definition of the most generic url patterns at last:
urlpatterns = [
path('upload_post/',views.upload_post,name='upload_post'),
path('add_comment/',views.add_comment,name='add_comment'),
path('<slug:slug>/',views.post_details,name='post_details'),
]
Hopefully this will work for you.
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 am attempting to render a form where the only field is a dropdown. I have the form, view, .html, url all set up. But when I access this url, it shows a different form and view and I suppose also a different .html. I am so confused on why this is happening as it had been working fine for quite some time so I obviously changed something.
forms.py
#this is the form for the dropdown
class ManifestDropDown(forms.Form):
References = forms.ModelChoiceField(queryset=Orders.objects.values_list('reference', flat=True).distinct(),
empty_label=None)
manifest_references.html
<!--html for dropdown-->
{% extends 'base.html' %}
{% block body %}
<div class="container">
<form method="POST" action="manifest">
{% csrf_token %}
{{ reference_list }}
<button type="submit" class="btn btn-primary" name="button">Submit</button>
</form>
</div>
{% endblock %}
views.py
#view for dropdown
def manifest_references(request):
if request.method == 'POST':
if form.is_valid():
reference_id = form.cleaned_data.get('References')
form.save()
query_results = Orders.objects.all()
reference_list = ManifestDropDown()
context = {
'query_results': query_results,
'reference_list': reference_list,
}
return render(request, 'manifest_references.html', context)
urls.py
url(r'^manifest_references', manifest_references, name='manifest_references'),
base.html
<!--showing the link to this url-->
...
<a class="dropdown-item" href="{% url 'manifest_references' %}">Edit Manifests</a>
When I access the url above - instead of showing the manifest_references view with the dropdown, it immediately jumps to a different view manifest which is referenced as the action in the manifest_references.html. Please someone help me determine why this is happening.
i created newsletters app with below code after that i have a URL : subscribe that perfectly work and save my email after that i want to add this ability in base page for example a user don't go to subscribe page and subscribed i want directly have access in base template and subscribe .
i want to know this because i want add login form to base page and have this problem with that .
this my code and this is my template
tnx for help.
views.py
from django.shortcuts import render
def Subscribe(request):
form = SiqnupNewslettersForm(request.POST or None)
if form.is_valid():
instance = form.save(commit=False)
if SignupNewsletters.objects.filter(email=instance.email).exists():
print("this email already taken ")
else :
instance.save()
context = {
'form':form
}
template_name = "subscribe.html"
return render(request,template_name,context)
def Unsubcribe(request):
form = SiqnupNewslettersForm(request.POST or None)
if form.is_valid():
instance = form.save(commit=False)
if SignupNewsletters.objects.filter(email= instance.email).exists():
SiqnupNewslettersForm.objects.filter(email = instance).delete()
else:
print("your email is not here")
context = {
'form' : form
}
template_name = "unsubscribe.html"
return render(request,template_name,context)
subscribe.html
{% block content %}
<div class="container">
<div class="row">
<form method="POST" action="">
{% csrf_token %}
<div class="form-group">
{{ form }}
</div>
<input type='submit' class="btn btn-primary"
value="submit">
</form>
</div>
</div>
{% endblock %}
urls.py
urlpatterns = [
path('subscribe/',views.Subscribe,name="subscribe"),
path('unsubscribe/',views.Unsubcribe,name= "unsubscribe"),
]
and finally what i have to do for add newsletter form in base page ?
base.html
I have a login form that I want to be available in all my views, so I created a context processor to add this form to every loaded context.
The problem is that {% csrf_token %} on the form template won't render the hidden input tag with the CSRF token value.
This is the context_processor order in settings.py:
TEMPLATE_CONTEXT_PROCESSORS = (
'django.contrib.auth.context_processors.auth',
'django.core.context_processors.debug',
'django.core.context_processors.i18n',
'django.core.context_processors.media',
'django.core.context_processors.static',
'django.core.context_processors.tz',
'django.contrib.messages.context_processors.messages',
'django.core.context_processors.request',
'django.core.context_processors.csrf',
'absolute.context_processors.absolute',
'myproject.app.context_processors.base',
)
And then the processor itself on app/context_processors.py:
from django.contrib.auth.forms import AuthenticationForm
def base(request):
context = dict()
if not request.user.is_authenticated():
context['login_form'] = AuthenticationForm()
return context
The form template:
{% load i18n %}
<form method="post" action="{% url "django.contrib.auth.views.login" %}">
{% csrf_token %}
<input type="hidden" name="next" value="{% if request.GET.next %}{{ request.GET.next }}{% else %}{{ request.get_full_path }}{% endif %}" />
{{ login_form.as_p }}
<input type="submit" class="button success expand" value="{% trans 'Login' %}" />
</form>
The HTML output for this form:
<form action="/accounts/login/" method="post">
<input type="hidden" value="/" name="next">
<p><label for="id_username">Usuário:</label> <input type="text" name="username" maxlength="254" id="id_username"></p>
<p><label for="id_password">Senha:</label> <input type="password" name="password" id="id_password"></p>
<input type="submit" value="Login" class="button success expand">
</form>
And the error I get when submitting it:
CSRF verification failed. Request aborted.
However, and as I'm only using class-based views, if I add a csrf_protect decorator the form will work, but like this I would have to declare the dispatch method in all my views:
from django.views.decorators.csrf import csrf_protect
class HomeView(TemplateView):
template_name = 'home.html'
#method_decorator(csrf_protect)
def dispatch(self, *args, **kwargs):
return super(HomeView, self).dispatch(*args, **kwargs)
Problem status
I gave up from putting the AuthenticationForm on all my views by creating a login form page. Anyway, it would still be awesome if someone could help me find a solution for this problem.
I've spent a couple of hours fighting an issue similar to the one you've described here. The {% csrf_token %} wasn't rendering anything and I was seeing this when in debug mode:
defaulttags.py:66: UserWarning: A {% csrf_token %} was used in a template, but the context did not provide the value. This is usually caused by not using RequestContext.
I was using a simple view that inherited from a TemplateView:
class MenuIndexView(TemplateView):
template_name = 'menu/index.html'
def get_context_data(self, **kwargs):
kwargs = super().get_context_data(**kwargs)
session = self.request.session
kwargs['zip_code'] = session.get('zip_code')
kwargs['calendar'] = helpers.get_menu_calendar(date.today() + timedelta(days=1), timedelta(days=14))
kwargs['forms'] = {'zip_code': forms.ZipCodeForm({'zip_code': session.get('zip_code')})}
return kwargs
After fussing around a bit under Django's I realized that pretty much no context at all was available where the tag was being generated (CsrfTokeNode on Django's defaulttags.py file):
class CsrfTokenNode(Node):
def render(self, context):
csrf_token = context.get('csrf_token', None)
if csrf_token:
if csrf_token == 'NOTPROVIDED':
return format_html("")
else:
return format_html("<input type='hidden' name='csrfmiddlewaretoken' value='{}' />", csrf_token)
else:
# It's very probable that the token is missing because of
# misconfiguration, so we raise a warning
if settings.DEBUG:
warnings.warn(
"A {% csrf_token %} was used in a template, but the context "
"did not provide the value. This is usually caused by not "
"using RequestContext."
)
return ''
In this point of the code I was only seeing an item within the context, with a zip_code key.
I opened up the main template file and realized that I was making a rookie mistake - this was my main template menu/index.html:
{% extends 'base.html' %}
{% block content %}
<div class="menu-order-meta zip_calendar">
<div class="ink-grid align-center">
<div class="column-group gutters half-vertical-padding medium">
{% include 'partials/menu/zip-code.html' with zip_code=zip_code only %}
</div>
</div>
</div>
{% endblock %}
I was including the form through a partial template and I was explicitly restricting the available context within that partial template - notice the with zip_code=zip_code only declaration - (and by doing so, implicitly turning the csrf_token context processor unavailable).
Maybe are you missing django.middleware.csrf.CsrfViewMiddleware in MIDDLEWARE_CLASSES ?
MIDDLEWARE_CLASSES = (
....
'django.middleware.csrf.CsrfViewMiddleware',
....
)