Not sure how to pass additional context data into various allauth forms which includes my own templates. For my own views I'm using get_context_data() which is working fine. I'm including small templates into a master template such as a header, footer, side bar etc. Everything is working except when allauth kicks in such as login, logout, email confirmation window etc my context variables are not passed so images in my left side bar are not showing up but allauth works fine.
I've tried a few things but I believe the ideal option is to inherit from allauth views for that function such as login, password reset, confirm email etc, supply my own context variable data.
In my accounts.views.py, I'm expecting this to fail as the template doesn't exist but the form still shows up and the UserProfile image isn't being shown in the left side bar.
from allauth.account.views import ConfirmEmailView
class EmailViewExt(ConfirmEmailView):
template_name = "account/signup_alternate1.html"
def get_context_data(self, **kwargs):
context = super(ConfirmEmailView).get_context_data(**kwargs)
context['userprofile'] = UserProfile.objects.get(user=self.request.user)
return context
In my template left_bar_base.html which is included from my overridden allauth template.
{% if userprofile.avatar_picture %}
<img src="{{ userprofile.avatar_picture.url }}" class="card-img-top" alt="...">
{% else %}
<img src="{% static 'placeholder.png' %}" class="card-img-top" alt="...">
{% endif %}
In my email_confirmation.html I have this at the top.
{% extends "ui/base.html" %}
{% load i18n %}
{% load account %}
{% block header %}
{% include "ui/loggedin_header.html" %}
{% endblock %}
{% block left %}
<div class="row no-gutters justify-content-start">
{% include 'ui/left_bar_base.html' %}
{% endblock %}
{% block content %}
... allauth template code...
Came across the solution.
My EmailViewExt(ConfirmEmailView) was never being called.
So instead of using allauths.urls I put this right above the allauths.urls.
urlpatterns = [
path('admin/', admin.site.urls),
path('accounts/email/', EmailViewCustom.as_view(), name="email"),
path('accounts/', include('allauth.urls')),
Now the context variable I've added is being passed into my templates. So I guess I have to add all of the urls from allauth for the ones I want to replace.
Related
I have a detail view that uses a Quiz object to display data stored in that object, like title and author. I want to have a button that links to a new page that displays different data from the same object. I don't know how to pass this data/object.
I can render the view and pass it the context of a specific quiz using an id but I want the id to change to be the id of the object from the initial page.
#assessement view
def assessment(request):
context = {
'quiz':Quiz.objects.get(id=1),
}
return render(request, 'quiz_app/assessment.html', context)
#detailview template for quiz
{% extends "quiz_app/base.html" %}
{% block content %}
<article class="quiz-detail">
<h1>{{ object.title }}</h1>
<h2>{{ object.question_amount }} Questions</h2>
<a class="btn" href="{% url 'quiz-assessment' %}">Start Quiz</a>
</article>
{% endblock content %}
#assessment template
{% extends "quiz_app/base.html" %}
{% block content %}
<h2>Assessment</h2>
<h2>Title is {{ quiz.title }}</h2>
{% endblock content %}
Then you should make another view for url quiz-assessment and pass the quiz pk as you did above in your assessment view.
def quiz_assessment(request,pk):
quiz = Quiz.objects.get (pk=pk)
return render (request,'assessment_template', {'quiz':quiz}
And in your url,pass the quiz id like this:
path ('<int:pk>/quiz/assessment /',views.quiz_assessment,name='quiz_assessment')
And in your template you can give url like this:
< a class="btn" href="{% url 'quiz_assessment' object.pk %}>
As suggested in the comments by #Robin Zigmond, you can do like this.
#assessement view
def assessment(request, qid):
context = {
'quiz':Quiz.objects.get(id=qid),
}
return render(request, 'quiz_app/assessment.html', context)
In the HTML file
#detailview template for quiz
{% extends "quiz_app/base.html" %}
{% block content %}
<article class="quiz-detail">
<h1>{{ object.title }}</h1>
<h2>{{ object.question_amount }} Questions</h2>
<a class="btn" href="{% url 'quiz-assessment' qid=object.id %}">Start Quiz</a>
</article>
{% endblock content %}
and in your urls.py change as:
path('quiz_asswssment/?P<int:qid>/', views.assessment, name="quiz_assessment")
Besides, what SammyJ has suggested, You can use the django sessions library or the django cache framework. You can temporarily store the information you need for the next view and access it whenever you want to.
In what Sammy J had suggested, you will always to have make sure that the queryset is passed in the context, otherwise it will not be rendered.
def assesment(self, request, id):
q = Quiz.objects.get(pk=id)
request.session["someData"] = q.name
request.session["qAmount] = q.amount
In your template file
<p>The title is : {{request.session.title}} and the amount is {{request.session.qamount}}
Note: Django sessions do not allow you to set a queryset as a session record, for that, you can use Django Cache framework.
Example
from django.core.cache import cache
cache.set('quiz', q)
getting cache -> cache.get('quiz')
Sessions framework docs : https://docs.djangoproject.com/en/2.2/topics/http/sessions/
Cache framework docs: https://docs.djangoproject.com/en/2.2/topics/cache/
I'm using this library to handle two factor auth for a django project, but i'm having some troubles: in my site, i added a setup.html page, i set the url on my urls.py file but i keep getting this error:
In template C:\Users\Us\lib\site-packages\allauth\templates\base.html, error at line 26
Reverse for 'account_email' not found. 'account_email' is not a valid view function or pattern name.
<li>Change E-mail</li>
Which is completely weird because i'm not trying to load a file called base.html but my own setup.html file, which is located in my project's folder (the path is project-folder>templates>setup.html). This is the setup.html that i would like to load from my own templates:
{% extends 'main/header.html' %}
{% load i18n %}
{% block content %}
<h1>
{% trans "Setup Two-Factor Authentication" %}
</h1>
<h4>
{% trans 'Step 1' %}:
</h4>
<p>
{% trans 'Scan the QR code below with a token generator of your choice (for instance Google Authenticator).' %}
</p>
<img src="{{ qr_code_url }}" />
<h4>
{% trans 'Step 2' %}:
</h4>
<p>
{% trans 'Input a token generated by the app:' %}
</p>
<form method="post">
{% csrf_token %}
{{ form.non_field_errors }}
{{ form.token.label }}: {{ form.token }}
<button type="submit">
{% trans 'Verify' %}
</button>
</form>
{% endblock %}
It looks like the module that i'm using, instead of loading MY setup.html will load something else, but i can't find a way to fix this.
Here is the view that i'm calling to handle the setup (it' the module's view):
https://github.com/percipient/django-allauth-2fa/blob/master/allauth_2fa/views.py
And here is my own urls.py, where the view that i mentioned is being called:
from django.urls import path
from . import views
from django.conf.urls import url, include
from django.conf.urls import url
from allauth_2fa import views as allauth_2fa_views
app_name = "main"
urlpatterns = [
path("setup/", allauth_2fa_views.TwoFactorSetup.as_view(), name="setup"),
path("", views.homepage, name="homepage"),
path("register/", views.register, name="register"),
path("logout/", views.logout_request, name="logout"),
path("login/", views.login_request, name="login"),
]
The TwoFactorSetup view is using a template setup.html in a folder allauth_2fa. So all you need to do is place your setup.html inside a folder with the same name: app_folder/templates/allauth_2fa/setup.html to override it.
Alternatively, subclass TwoFactorSetup and just change the template_name attribute to point to your template and use that view in your urls.py:
from allauth_2fa.views import TwoFactorSetup
class MySetup(TwoFactorSetup):
template_name = 'my_app/setup.html'
i'm using the django built in authentication system and in my login template i have this code :
login.html:
{% block title %}Login{% endblock %}
{% block content %}
<h2>Login</h2>
{% if user.is_authenticated%}
you are already logged in
{% else %}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Login</button>
</form>
{% endif %}
{% endblock %}
but what i really want to do is to redirect the user to the home page if he tries to access login page while already logged in, but i am new to django so i don't know how to do that.
For django>=1.11 you can set redirect_authenticated_user parameter to True in its url in url_patterns to do the redirect, like this:
from django.contrib.auth import views as auth_views
urlpatterns = [
url(r'^login/', auth_views.LoginView.as_view(redirect_authenticated_user=True), name='login'),
]
read the document for more information.
and also set LOGIN_REDIRECT_URL in your setting file to your index url or its name:
LOGIN_REDIRECT_URL = '/index/'
In your `settings.py' add this:
LOGIN_REDIRECT_URL = 'index'
if the url name of your index is 'index', else put the correct url name
You can do it in your views.py file.
def login(request):
if request.method =="get":
if request.user.is_authenticated:
return render(// youre code)
I have integrated djangocms blog in my project. In homepage sidebar i want to display latest blog posts. Problem is, my homepage is django-cms page and i can't get blog post objects. urls.py:
urlpatterns = i18n_patterns('',
url(r'^admin/', include(admin.site.urls)),
.....
url(r'djangocms_blog/', include('djangocms_blog.urls', namespace='djangocms_blog')),
url(r'^', include('cms.urls')),
)
Somehow here in main.html i should be able to get blog records:
{% extends "base.html" %}
<nav class="secondary-menu">
<ul class="nav">
<!-- i need display them here -->
</ul>
</nav>
Is there any elegant way to do this?
Use either an assignment_tag or an inclusion_tag:
Templatetag
# templatetags/blog_tags.py
from django import template
from djangocms_blog.models import Post
register = template.Library()
#register.assignment_tag()
def latest_posts_as(limit=5):
return Post.objects.order_by('-date_published')[0:limit]
#register.inclusion_tag('latest_posts.html', takes_context=True)
def latest_posts_inline(context, limit=5):
qs = Post.objects.order_by('-date_published')[0:limit]
context.update({'posts': qs})
return context
Snippet for inclusion tag
<!-- latest_posts.html -->
{% for post in posts %}
<p>{{ post }}</p>
{% endfor %}
Your home/whatever template
<!-- your_template.html -->
{% load blog_tags %}
<div>
<!-- using assignment_tag -->
{% latest_posts_as limit=20 as posts %}
{% for post in posts %}
<p>{{ post }}</p>
{% endfor %}
<!-- using inclusion_tag -->
{% latest_posts_inline limit=10 %}
</div>
The limit is optional - but could be handy :)
Came up with other solution. Created new django-cms plugin:
class BlogLatestEntriesPluginNav(BlogLatestEntriesPlugin):
name = _('Navigition latest blog entries')
render_template = 'latest_entries_nav.html'
plugin_pool.register_plugin(BlogLatestEntriesPluginNav)
where BlogLatestEntriesPlugin is plugin from djangocms_blog app. And created new template 'latest_entries_nav.html'. Then in main.html
<ul class="nav">
{% placeholder "left_sidebar" %}
</ul>
created placeholder and added that plugin.
I have three apps in my Django project that correspond to separate parts of the website. All three parts are accessible from the navigation menu, defined in common base.html template.
I want to be able to identify the app that called the template to add an 'active' css class to the menu option corresponding to the active part of the site.
What's the best way to do it, short of modifying each view to pass an additional variable to the template?
The most non-invasive way would be:
Write a template tag that generates your menu.
Update your context with the application name.
Pass this to the template tag and modify the css accordingly.
I'll explain the second bit, as writing custom template tags is covered in detail in the django documentation.
To update the context; we need some middleware. This should do what you need:
class SetApplicationName(object):
def process_view(self, request, view_func, view_args, view_kwargs):
request.current_app = view_func.__module__.split('.')[0]
Place this somewhere django can find it (in any directory in PYTHONPATH), and add it to your middleware classes. Also, make sure you have django.core.context_processors.request in your template context processors.
In your templates, now you have {{ request.current_app }} which should point the app name.
Your template tag should be something like {% navigation_menu request.current_app %}, and you can then modify your menu css accordingly.
I would try "overriding" the {%block%} tag.
In your base.html template put something like:
{%block navigation_bar%}
<div class="regular">First app</div>
<div class="regular">Second app</div>
<div class="regular">Third app</div>
{%endblock%}
In your descendant templates, change that navitation_bar block with other. first_app_base.html looks like:
{%extends "base.html"%}
{%block navigation_bar%}
<div class="active">First app</div>
<div class="regular">Second app</div>
<div class="regular">Third app</div>
{%endblock%}
If you define navigation menu in separate template, you could include it with additional context.
base.html:
{% block navigation %}Here will be navigation{% endblock %}
template_from_some_app.html:
{% extends "base.html" %}
{% block navigation %}
{% include "navigation.html" with active_app='second_app' %}
{% endblock %}
navigation.html:
<ul class="nav">
<li {% if active_app == 'first_app' %} class="active">{% endif %}>
First app
</li>
<li {% if active_app == 'second_app' %} class="active">{% endif %}>
Second app
</li>
<li {% if active_app == 'third_app' %} class="active">{% endif %}>
Third app
</li>
</ul>