How to switch wagtail homepage depending on user logged in status - python

I have previously been using path("", include(wagtail_urls)) for my home_page url which displays the template at home/home_page.html correctly
I wish to however display different pages depending on whether a user is logged in or not so have changed this to:
def logged_in_switch_view(logged_in_view, logged_out_view):
'''switches views dependedn on logon status'''
def inner_view(request, *args, **kwargs):
if request.user.is_authenticated:
return logged_in_view(request, *args, **kwargs)
return logged_out_view(request, *args, **kwargs)
return inner_view
urlpatterns = [
path("",
logged_in_switch_view(
TemplateView.as_view(template_name="home/home_page.html")),
TemplateView.as_view(template_name="home/not_authenticated.html")),
name="home"),
]
With this approach (directly specifying the template rather than using wagtail_urls) the home page does not display correctly when logged in, in that all the wagtail tags in the html e.g. the blog posts are not displaying
home_page.html
{% extends "base.html" %}
{% load wagtailcore_tags wagtailimages_tags %}
{% block content %}
<main class="container">
{% for post in page.blogs %}
{% with post=post.specific %}
<div class="col-md-8 mx-auto px-auto">
<div class="row border rounded overflow-auto flex-md-row mb-4 shadow-sm position-relative ">
<div class="col p-4 d-flex flex-column position-static">
<strong class="d-inline-block mb-2 text-primary">{{ post.category }}</strong>
<div class="mb-1 text-muted">{{ post.date }}</div>
<h3 class="mb-0">{{ post.title }}</h3>
<p>{{post.intro}}</p>
</div>
<div class="col-auto my-auto py-2 px-2 d-none d-lg-block">
<a href="{% pageurl post %}" class="stretched-link">
{% with post.main_image as main_image %}{% if main_image %}
{% image main_image min-250x250 max-350x350%}
{% endif %}{% endwith %}
</a>
</div>
</div>
</div>
{% endwith %}
{% endfor %}
</main>
{% endblock %}
How should I specify the home_page in the logged_in_switch_view function?

The include(wagtail_urls) pulls in Wagtail's page handling logic for selecting which page should be returned for a given URL. If you swap that line out with your own code, you're effectively swapping out all of Wagtail...
First, consider whether you're reinventing the page privacy feature that Wagtail already provides. If you want the site as a whole to require a login, and non-logged-in users to be given a blanket generic login form, you can enable this using the Privacy control under the Settings tab (or in the top right corner on older Wagtail releases) when editing the homepage, and set WAGTAIL_FRONTEND_LOGIN_TEMPLATE = "home/not_authenticated.html" in your project settings file.
If you just want to swap the template for the homepage specifically, you can do that by defining a get_template method on your HomePage model:
class HomePage(Page):
# ...
def get_template(self, request, *args, **kwargs):
if request.user.is_authenticated:
return "home/home_page.html"
else:
return "home/not_authenticated.html"
This way, your homepage will select one template or the other, but still keep the page object available on the template.

Related

how to use class based views for a single page blog with pagination in django

this is the error messag am getting in a picture someone should please help me solve this problem i have been on it for the past 3days,
i have a single blog which is handled by multiple author or admin,so i decided to use class based views and when i create a new post gives an error saying i need blog_detail.html,since i dont have detail blog so i created a Detailview then adding my template_name = 'mymainblogpage.html' so once i create new post it will get posted but wont show the post but will only show the pagination,besides i cant search by post id for example http://127.0.0.1:8000/pages/blog/49/ i just get nothing here is my code.
views.py
def blog(request):
blog_post = Blog.objects.all()
ordering = ['-timestamp']
paginator = Paginator(blog_post, 2)
page_request_var = 'page'
page = request.GET.get(page_request_var)
try:
paginated_queryset = paginator.page(page)
except PageNotAnInteger:
paginated_queryset = paginator.page(2)
except EmptyPage:
paginated_queryset = paginator.page(paginator.num_pages)
context = {
'queryset': paginated_queryset,
'page_request_var': page_request_var
}
return render(request, 'pages/blog.html', context)
class BlogDetailView(DetailView):
model = Blog
template_name = 'pages/blog.html'
context_object_name = 'blog'
urls.py
path('blog/', BlogDetailView.as_view(), name='blog'),
path('blog/<int:pk>/', BlogDetailView.as_view(), name='blog-detail'),
models.py
def get_absolute_url(self):
return reverse('blog-detail', kwargs={'pk': self.pk})
blog.html
<br><p></p>
<section class="ftco-section bg-light" id="blog-section">
<div class="container">
<div class="row justify-content-center mb-5 pb-5">
<div class="col-md-10 heading-section text-center ftco-animate">
<h2 class="mb-4">Gets Every Single Updates Here</h2>
<p>Far far away, behind the word mountains, far from the countries Vokalia and Consonantia</p>
</div>
</div>
<div class="container">
<div class="row justify-content-center mb-5 pb-5">
<div class="col-lg-8 ftco-animate">
{% for blog in queryset %}
<h2 class="text-center">{{ blog.title }}</h2>
<div class="meta mb-3 text-center">
<div><h6><span><a href = "">written By {{ blog.user }}</span><small class="date"><i class="icon-clock"></i> {{ blog.timestamp|timesince }} ago</small><a/></h6>
</div>
</div>
<div><small class="icon-eye text-danger">{{ blog.view_count }}</small></div>
<div class="meta mb-3 text-center">
<h5>{% for cat in blog.categories.all %}<span class="btn btn-dark">{{ cat }}</span> {% endfor %}</h5>
</div>
<p class="text-center">{{ blog.overview }}</p>
{% endfor %}
<nav aria-label="pagination">
<ul class="pagination pagination-circle pg-blue">
{% if queryset.has_previous %}
<li class="page-item">Previous</li>
{% endif %}
<li class="page-item active">{{ queryset.number }}</li>
</a>
</li>
{% if queryset.has_next %}
<li class="page-item">Next</li>
{% endif %}
</ul>
</nav>
{% if is_paginated %}
<nav aria-label="pagination">
<ul class="pagination pagination-circle pg-blue">
{% if queryset.has_previous %}
<li class="page-item">Previous</li>
{% endif %}
<li class="page-item active">{{ queryset.number }}</li>
</a>
</li>
{% if queryset.has_next %}
<li class="page-item">Next</li>
{% endif %}
</ul>
</nav>
{% endif %}
</div>
</div>
</div>
</div>
</section>
You pagination isn't showing because you are passing context variable 'page_request_var': page_request_var instead of 'page_request_var': page
so change it because page_request_var is just a string 'page'.
If you need to use class-based list view then
from django.views.generic import ListView
class PostListView(ListView):
queryset = Post.published.all()
context_object_name = 'posts' # by default class list view uses object_list.
paginate_by = 2 # number of objects/posts per page
template_name = 'pages/blog.html' # by default uses <appname>/<modelname>_<view_type>.html
also, I would recommend using different templates for list and detail views because you are just searching the same template using so I think that may be a problem.

How to use Django Haystack whoosh search field in multiple application templates

I have implemented a working Django 1.6 haystack/whoosh search field following Mike Hibbert's tutorial:https://www.youtube.com/watch?v=B-n6_m66TmA. The implementation works in a twitter bootstrap search field in the navbar in the url 'search'. I'd like to use the implementation in several pages in my application but it doesn't work.
I've tried with implementing the search.html code in other pages with search bars but it changes the search url prefix from 'search/...' to the page url, e.g. to 'front/...' on the frontpage. I've also tried to include the search.html in other pages, both as the block content and with an include tag in the template but it hasn't worked.
# in app/templates/search/indexes/search.html
{% extends 'base_searches.html' %}
{% block content %}
<form method="get" action=".">
<table>
<tr><th><label for="id_q"></label></th><td><input type="text" id="id_q"
name="q" placeholder="Search..." class="form-control" /><button
class="btn btn-success" type="submit" value="Search"><spaclass="glyphicon
glyphicon-search"></span></button></td></tr>
<tr>
<td> </td>
{% if query %}
{% for result in page.object_list %}
<div class="alert alert-success" role="alert">
Hi, {{ user }}, here's the found database match for your search
<a href="{{ result.object.get_absolute_url }}">
{{result.object.title }}.</a></div>
{% empty %}
<div class="alert alert-info" role="alert">
<strong>Hi {{ user }}, there's no match found in the
database for your search !.</strong>
</div>
{% endfor %}
{% endif %}
<div class="col-xs-6 col-sm-3 sidebar-offcanvas" id="sidebar">
<!--/.sidebar-offcanvas-->
<!--/row-->
<hr>
<td>
</td>
</tr>
</table>
</form>
</body>
</html>
{% endblock %}
# in models.py for each indexed model field
def get_absolute_url(self):
return '%s' % self.id
# in app/templates/base_searches.html
<form class="navbar-form navbar-right" id="search">{% csrf_token %}
<center><h> <td colspan="1" id="content">{% block content %}}
{% endblock %} </center></td></h>
<ul id="search-results">
</ul>
</form>
in urls.py
from haystack.query import SearchQuerySet
url(r'^search/',include('haystack.urls'),name='haystack_search'),
# in search_indexes.py
from haystack import indexes
from app.models import Article
class ArticleIndex(indexes.SearchIndex, indexes.Indexable):
text= indexes.CharField(document=True,use_template=True)
content = indexes.CharField(model_attr='description')
content_auto = indexes.EdgeNgramField(model_attr='title')
def get_model(self):
return Article
def index_queryset(self, using=None):
"""used when the entire index for model is updated """
return self.get_model().objects.all()
# in app/templates/search/indexes/appname/article_text.txt
{{ object.title }}
{{ object.content}}
How do I include the search.html in other pages, as I've included it in the navbar in base_searches.html, and maintain the prefix search/..searchresult for the get_absolut_url function for the search result object and not the url prefix for other pages that I'm trying to include it in, e.g. front/..searchresult ? when trying to implement it in the frontpage with url front/, or are there better ways to use the haystack whoosh search in search fields in multiple application pages ?
I have solved this problem by adding http://{{ request.get_host }}/search" to the search form action.
`<form method="get" action="http://{{ request.get_host }}/search"`
The action="." will reference to your current page and the request will be redirected to your current view. With adding the host URL to your action it will redirect your query to the search view no matter on which page you are.

Is it possible to pass a variable as a CSS class to a Django html template?

Pretty much a Django any Python noob - been studying for a month or so and watching tutorials...so I know enough to be dangerous. I'm trying to randomize the CSS class in an HTML template. I'm using a custom Bootstrap template to display database entries as cards, and I want to randomize the background. I've got the basics down, but haven't been able to figure out how to randomize the CSS class value in the actual html template.
I've tried the randomizing the value in the relevant Django views template. Searched through 2.2 docs, stack, google, etc., but so far no joy
views.py:
import random
from django.shortcuts import render
from compliments.models import Compliments
def compliment(request):
compliment = Compliments.objects.all()
return render(request, 'compliments/home.html', {'compliment': compliment})
classList = [
'bg-secondary', 'bg-success', 'bg-danger', 'bg-warning',
'bg-info', 'bg-light', 'bg-dark'
]
css_class = random.choice(classList)
my HTML:
{% extends 'base.html' %}
{% block body %}
<div class="row">
<div class="col-12">
<h4 class="mb-4">Compliments</h4>
</div> <!-- end col -->
</div><!-- end row -->
<div class="row">
{% for compliment in compliment %}
<div class="col-md-4">
<div class="card {{ compliment.css_class }} text-white">
<div class="card-body">
<p class="card-text">{{ compliment.body }}</p>
Select
</div> <!-- end card-body-->
</div> <!-- end card-->
</div> <!-- end col-->
{% endfor %}
</div>
{% endblock%}
I was expecting that I could get "css_class" from my views to show up in the HTML template at {{ complment.css_class }}, but inspecting the class attributes show that it is not being rendered at all (just blank).
You're getting to return before you set the css_class and don't add it to your context
def compliment(request):
compliment = Compliments.objects.all()
classList = [
'bg-secondary', 'bg-success', 'bg-danger', 'bg-warning',
'bg-info', 'bg-light', 'bg-dark'
]
css_class = random.choice(classList)
return render(request, 'compliments/home.html', {'compliment': compliment, 'css_class`: css_class})
Create a template tag (ie in the directory templatetags create the following file with name mytags.py as an example
import random
from django import template
register = template.Library()
classList = [
'bg-secondary', 'bg-success', 'bg-danger', 'bg-warning',
'bg-info', 'bg-light', 'bg-dark'
]
#register.simple_tag
def random_css(a):
return css_class = random.choice(classList)
In html
{% load mytags %}
<div class="card {{ compliment|random_css }} text-white">
Here is the working version after guidance from HenryM and the Custom template tags and tilters section of the Django docs.
myapp/templatetags/mytags.py:
import random
from django import template
register = template.Library()
classList = [
'bg-secondary', 'bg-success', 'bg-danger', 'bg-warning', 'bg-info',
'bg-light', 'bg-dark'
]
#register.filter
def random_css(a):
return random.choice(classList)
Relevant section of views.py:
def compliment(request):
compliment = Compliments.objects.all()
return render(request, 'compliments/home.html', {
'compliment': compliment
})
And the HTML to render it:
{% extends 'accounts/base.html' %}
{% load mytags %}
{% block body %}
<div class="row">
<div class="col-12">
<h4 class="mb-4">Compliments</h4>
</div>
<!-- end col -->
</div>
<!-- end row -->
<div class="row">
{% for compliment in compliment %}
<div class="col-md-4">
<div class="card {{ compliment|random_css }} text-white">
<div class="card-body">
<p class="card-text">{{ compliment.body }}</p>
Select
</div>
<!-- end card-body-->
</div>
<!-- end card-->
</div>
{% endfor %}
<!-- end col-->
</div>
{% endblock%}

Inserting ListView Template in a section of the Homepage using Django 1.11

I have a ListView Template in Django 1.11 that renders to group_list.html. However I want the same view to show in a column in the home page
I also have screenshots below if that helps understanding what I am trying to achieve
I have tried different ways to use {% include 'some.html' %}
1) I tried to make a html page and include it in homepage. but it keeps giving errors
2) I tried to change the group_list.html page into a (insert template) that and tried to insert that, in both the index page and created another template view for groups. but that is giving errors too
Below are my views and templates
Views.py
class GroupCreate(LoginRequiredMixin, CreateView):
model = Group
fields = ('name', 'description')
class GroupList(ListView):
model = Group
class GroupDetail(DetailView):
model = Group
Below is my Index.html and group_list.html
INDEX.HTML
{% extends 'base.html' %}
{% block body %}
<div class="col-md-8" style="background-color:white; border-right:1px solid grey;">
<h4>Groups</h4>
<p>Join a group or make a new Group.</p>
<a style="float:left" class="btn btn-success" href="{% url 'groups:new' %}">Start a Group</a>
<div class="content">
<!--{ % include 'groups/some.html' % } I am trying to insert my -->
</div>
</div>
<div class="col-md-4" style=background-color:white">
<h4>Second Coloumn</h4>
</div>
{% endblock %}
Below is my group_list.html
{% extends 'groups/group_base.html' %}
{% block pre_group %}
<div class="col-md-4">
<div>
<h2>Welcome Back
{{group.user.username}}
</h2>
<h3>Groups</h3>
<p>Welcome to the groups page! Select the Group with the shared interest</p>
</div>
<div>
{% if user.is_authenticated %}
<a class="btn btn-warning" href="{% url 'groups:new' %}"><span class="glyphicon glyphicon-plus-sign"></span> Create a New Group</a>
{% endif %}
</div>
</div>
{% endblock %}
{% block content %}
<div class="col-md-8">
<div class="list-group">
{% for group in object_list %}
<a class="list-group-item" href="{% url 'groups:single' slug=group.slug %}">
<h3 class="list-group-item-heading">{{group.name}}</h3>
<div class="list-group-item-text container-fluid">
{{group.description_html|safe}}
<div class="row">
<div class="col-md-4">
<span class="badge">{{group.members.count}}</span> member{{group.members.count|pluralize}}
</div>
<div class="col-md-4">
<span class="badge">{{group.posts.count}}</span> post{{group.posts.count|pluralize}}
</div>
</div>
</div>
</a>
{% endfor %}
</div>
</div>
{% endblock %}
The HomePage View comes from the root Views they are below
View.py(root directory)
from django.views.generic import TemplateView
class Homepage(TemplateView):
template_name = 'index.html'
class LoggedIn(TemplateView):
template_name = 'test.html'
class LoggedOut(TemplateView):
template_name = 'thanks.html'
I am still learning Django while working on my 1st independent project. I did a some research but could not solve this
I want a list view like this to show on a section of the HomePage
Currently the view works perfectly well on the groups page
In your homepage view you can override get_context_data and add the groups to the context.
class Homepage(TemplateView):
template_name = 'index.html'
def get_context_data(self, **kwargs):
context = super(Homepage, self).get_context_data(**kwargs)
context['object_list'] = Group.objects.all()
return context
In the index.html, you'll have to copy the code from your group_list.html template. To prevent duplication, you could move the code from the content block into a include_groups.html template, then use {% include 'include_groups.html' %} in yourindex.htmlandgroup_list.html` templates.
In this case, since your Homepage view is just a template view, you could use a ListView instead.
class Homepage(ListView):
model = Group
template = 'index.html'
Whichever option you go for, it's useful to understand how to override get_context_data in class based views.

Django - Have a class based view and Crispy form parrallell to each other on same page

Using Django, I am making a site that displays tickets. On the login page, I want it to where there is a preview area of existing tickets to the left of the login form. I am able to make both pages seperately, but I can not figure out how to make them co-exist side by side. I am also using jinja2 templating. I've been trying at this for 2 days, and I have read the tutorials over and over. Here is how I have it:
url.py:
urlpatterns = patterns('',
url(r'', include('ticket_app.urls')),
url(r'^accounts/login/$', login, {'authentication_form': forms.LoginForm}, name='login'),
)
views.py Note: Request is the database table object:
class PreviewList(ListView):
model = Request
form.py:
class LoginForm(AuthenticationForm):
def __init__(self, *args, **kwargs):
super(LoginForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_class = 'form-horizontal'
self.helper.label_class = 'col-lg-2'
self.helper.field_class = 'col-lg-8'
self.helper.form_tag = False
self.helper.layout = Layout(
Field('username', placeholder="Username", css_class='input-xlarge'),
Field('password', placeholder="Password", css_class='input-xlarge'),
FormActions(
Submit('login', 'Login', css_class="btn-primary"),
)
base.html(short version):
<h1>{% block page_title %}Preview of tickets{% endblock page_title %}</h1>
{% block preview %}
{% endblock preview %}
{% block login %}
{% endblock login %}
preview.html:
{% extends 'base.html'%}
{% block preview %}
<div class="span6">
<ul class="list-group">
{% if object_list %}
{% for item in object_list %}
<li class="list-group-item">{{item.date_due}} - {{item.desctription}}
<span class="badge">
{% if item.user_assigned %}
<span class="badge"style="color:green"> assigned </span>
{% else %}<span class="badge" style="color:red">unassigned</span>
{% endif %}
</li>
{% endfor %}
{% else %}
<p>Yay! No ticket requests found!</p>
{% endif %}
</div>
{% endblock preview %}
login.html:
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block login %}
<div class="container" style="padding-bottom: 70px;">
<div class='row'>
<div class='col-md-6 col-md-offset-3'>
<div class="well">
<legend>Sign in to Site</legend>
<form method="post" action="{% url 'django.contrib.auth.views.login' %}" class="form-horizontal">
{% crispy form %}
<input type="hidden" name="next" value="{{ next }}"/>
</form>
</div>
</div>
</div>
</div>
{% endblock login %}
There are multiple ways to accomplish this. For example, you could create your own login view that 'extends' the one from django.contrib.auth:
from django.contrib.auth.views import login
def login_with_preview(request, extra_context=None, *args, **kwargs):
if extra_context is None:
extra_context = {}
extra_context['object_list'] = Request.objects.all()
return login(request, authentication_form=LoginForm, extra_context=extra_context, *args, **kwargs)
And then use login_with_preview in your url conf and merge your two templates.
Another possibility is to create a custom template tag. This is especially nice if you want to show this preview list in different places:
#register.inclusion_tag("yourapp/preview_list.html")
def ticket_preview_list():
return {'object_list': Request.objects.all()}
preview_list.html should only contain the template code that, right now, is in your preview template block. You need to make sure that template doesn't extend base.html; that would mess things up. The usual template tag setup steps apply.
You could create one view that renders the login form and the preview data

Categories

Resources