Handle PageNotAnInteger error or Disable the elided notation - django

I want to make elided page pagination like 1,2,3...8,9,10. So here is my code
in models.py
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=200)
email = models.EmailField()
in views.py
from django.shortcuts import render
from .models import Author
from django.core.paginator import Paginator
def author(request):
authors = Author.objects.all()
paginator = Paginator(authors, 2)
page_number = request.GET.get("page")
authors_data = paginator.get_page(page_number)
elided_page = paginator.get_elided_page_range(page_number, on_each_side=3,on_ends=2)
context = {
"authors" : authors_data,
"elided_data" : elided_page,
}
return render (request, "authors.html", context)
in author.html
# all authors
{% for author in authors %}
<p> {{author}}</p>
{% endfor %}
# pagination part
{% for i in elided_data %}
{{i}}
{% endfor %}
this way I get elided pagination like 1,2,3...9,10 perfectly. But problem is when i click on three dot (...) then it shows me pageNotAnInteger error. Is there any way to disable the link of that three dot?

After spending so much time and research I discovered the answer.
so in views.py remove elided_page variable and elided_data key from context dict.
from django.shortcuts import render
from .models import Author
from django.core.paginator import Paginator
def author(request):
authors = Author.objects.all()
paginator = Paginator(authors, 2)
page_number = request.GET.get("page")
authors_data = paginator.get_page(page_number)
context = {
"authors" : authors_data,
}
return render (request, "authors.html", context)
and in author.html
# retrive all authors
{% for author in authors %}
<p> {{author}}</p>
{% endfor %}
# pagination part
{% for i in authors.paginator.get_elided_page_range %}
{% if i == authors.paginator.ELLIPSIS %}
<span class="page-link">...</span>
{% else %}
<a class="page-link" href="?page={{ i }}">{{ i }}</a>
{% endif %}
{% endfor %}

Related

django 3 redirect with pk in form verification

#MODS- Although it has been asked on here before I can not find a suitable answer in Django 3, please read through all I have tried before deleting
Preamble:
I am working through This Tutorial that is taught in Django 1, I am following it but making necessary changes for Django 3.
QUESTION:
I receive an error when loading my page with a form on it.
HTML for the form page:
{% block title %}Start a New Topic{% endblock %}
{% block breadcrumb %}
<li class="breadcrumb-item">Boards</li>
<li class="breadcrumb-item">{{ board.name }}</li>
<li class="breadcrumb-item active">New topic</li>
{% endblock %}
{% block content %}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-success">Post</button>
</form>
{% endblock %}
Base HTML:
{% block title %}Start a New Topic{% endblock %}
{% block breadcrumb %}
<li class="breadcrumb-item">Boards</li>
<li class="breadcrumb-item">{{ board.name }}</li>
<li class="breadcrumb-item active">New topic</li>
{% endblock %}
{% block content %}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-success">Post</button>
</form>
{% endblock %}
urls.py
from django.contrib import admin
from django.urls import path , re_path
#uses path and re_path for regex when needed.
from boards import views
urlpatterns = [
path('admin/', admin.site.urls),
re_path('boards/(?P<pk>\d+)/$', views.board_topics, name='board_topics'),
re_path('boards/(?P<pk>\d+)/new/$', views.new_topic, name='new_topic'),
path('', views.home,name='home'),
]
Forms.py
from .models import Topic
class NewTopicForm(forms.ModelForm):
message = forms.CharField(
widget=forms.Textarea(
attrs={'rows': 5, 'placeholder': 'What is on your mind?'}
),
max_length=4000,
help_text='The max length of the text is 4000.'
)
class Meta:
model = Topic
fields = ['subject', 'message']
views.py
from .models import Board, Topic, Post
from django.contrib.auth.models import User
from .forms import NewTopicForm
from django.http import HttpResponseRedirect
# Create your views here.
def home(request):
boards = Board.objects.all()
return render(request, 'home.html', {'boards': boards})
def board_topics(request, pk):
try:
board = Board.objects.get(pk=pk)
except Board.DoesNotExist:
raise Http404
return render(request, 'topics.html', {'board': board})
def new_topic(request, pk):
board = Board.objects.get(pk=pk)
user = User.objects.first() # TODO: get the currently logged in user
if request.method == 'POST':
form = NewTopicForm(request.POST)
if form.is_valid():
topic = form.save()
return HttpResponseRedirect('/')
else:
form = NewTopicForm()
return render(request, 'new_topic.html', {'form': form})
I believe my issue is coming from return HttpResponseRedirect('/').
in the tutorial they use a redirect
return redirect('board_topics', pk=board.pk)
However to my knowledge this is not possible in django 3. Also when I looked on the official django 3.1 documentation in forms they use a HttpResponseRedirect aswell.
I have tried using a render but was not able to make it work either.
Any suggestions? I have been stuck on this for a few hours and want to get past it.
Try using reverse:
from django.shortcuts import reverse
... your form ...
return redirect(reverse('board_topics', kwargs={'pk': board.pk}))
btw the regular redirect should also work, try it.
edit
you actually need to pass board as a parameter in your context in your form view:
return render(request, 'new_topic.html', {'form': form, 'board': board})

Django Search Implementation, conditional routing

I am trying to implement basic search functionality with Django. Could use help with accessing query inputs from forms in templates in functional or class based views. Intended functionality:
If exact search query page exists, display that page
If there is a page title that contains what was queried, show results of all
If neither, display a message stating no results found
I'm just learning, so I tried functional views and class based views. I've spent a really long time on documentation/videos/textbooks and don't see how to get the intended behavior out of class-based view. I understand collecting object_list and getting query_set, but how do you then route to those three different conditions. I tried overriding dispatch() and as_views() method to no avail. Tried with a Django form class and without.
For some reason, the functional view keeps executing the first try statement instead of throwing a DoesNotExist exception when the exact match isn't found. So it shows the entry page instead of the search results page. It seems like the request.GET is None type no matter what, as when I try to print nothing shows up.
urls.py
from re import search
from django.urls import path
from . import views
from .views import IndexPageView, SearchView
app_name = "wiki"
urlpatterns = [
# ex: /wiki/
path("", views.index, name="index"),
# path("", IndexPageView.as_view(), name="index"),
# ex: /wiki/EntryPageName
path("wiki/<str:entry>/", views.displayEntry, name="displayEntry"),
# path("wiki/search/", views.searchView, name="searchView")
path("wiki/search/", SearchView.as_view(), name="searchView")
]
model
class Entry(models.Model):
title = models.CharField(max_length=64)
def __str__(self):
return f"{self.title}"
content = models.TextField()
views.py
def searchView(request):
searchedTerm = request.GET.get('q')
try:
exactMatch = Entry.objects.get(title=searchedTerm)
entryTitle = exactMatch.title
entryHTML = markdown2.markdown(exactMatch.content)
return render(request, "encyclopedia/displayEntry.html", {
"entryTitle": entryTitle,
"entryHTML": entryHTML
})
except:
try:
searchResults = Entry.objects.filter(Q(title__icontains=searchedTerm))
return render(request, "encyclopedia/searchResults.html", {
"searchResults": searchResults,
"searchedTerm": searchedTerm
})
except:
return render(request, "encyclopedia/searchResults.html", {
"emptyResults": f"No entries found matching: {searchedTerm}",
"searchedTerm": searchedTerm
})
class SearchView(ListView):
template_name = "encyclopedia/searchResults.html"
model = Entry
context_object_name = "searchList"
def get_queryset(self):
searchedTerm = self.request.GET.get('q')
try:
searchResults = Entry.objects.get(title=searchedTerm)
return searchResults
except:
try:
searchResults = Entry.objects.filter(Q(title__icontains=searchedTerm))
return searchResults
except:
pass
def as_view():
searchedTerm = self.request.GET.get('q')
try:
exactMatch = Entry.objects.get(title=searchedTerm)
entryTitle = exactMatch.title
entryHTML = markdown2.markdown(exactMatch.content)
return render(request, "encyclopedia/displayEntry.html", {
"entryTitle": entryTitle,
"entryHTML": entryHTML,
})
except:
searchResults = Entry.objects.filter(Q(title__icontains=searchedTerm))
return render(request, "encyclopedia/searchResults.html", {
"searchResults": searchResults,
"searchedTerm": searchedTerm
})
else:
return render(request, "encyclopedia/searchResults.html", {
"emptyResults": f"No entries found matching: {searchedTerm}",
"searchedTerm": searchedTerm
})
search form from layout.html
<form action="{% url 'wiki:search' %}" method="GET">
<input class="search" type="text" name="q" placeholder="Search Encyclopedia">
<!-- <input type="submit" value="submit"> -->
</form>
display entry page template
{% extends "encyclopedia/layout.html" %}
{% block title %}
{% if entryTitle %}
{{ entryTitle }}
{% else %}
Page Not Found!
{% endif %}
{% endblock %}
{% block body %}
{% if entryHTML %}
{{ entryHTML|safe }}
{% else %}
<p>This page does not exist yet.</p>
<p>Check your spelling or create a new entry!</p>
<p>?? {{ testPrint }}</p>
{% endif %}
{% endblock %}
search results page
{% extends "encyclopedia/layout.html" %}
{% block title %}
Search Results: {{ searchedTerm }}
{% endblock %}
{% block body %}
{% if searchResults %}
<h3>Search Results</h3>
<ul>
{% for result in searchResults %}
<li>{{ result.title }}</li>
{% endfor %}
</ul>
{% else %}
<h3>{{ emptyResults }}</h3>
{% endif %}
{% endblock %}
Models
class Entry(models.Model):
title = models.CharField(max_length=64)
content = models.TextField()
def __str__(self):
return self.title
Views
from django.views.generic.list import ListView
from django.views.generic.detail import DetailView
from app.models import Entry
class EntryListView(ListView):
model = Entry
paginate_by = 100 # if pagination is desired
def get_queryset(self):
queryset = super().get_queryset()
q = self.request.GET.get("q")
if q:
queryset = queryset.filter(title__icontains=q)
return queryset
class EntryDetailView(DetailView):
model = Entry
Urls
from django.urls import path
from app.views import EntryListView, EntryDetailView
urlpatterns = [
path('', EntryListView.as_view(), name='entry-list'),
path('<int:pk>/', ArticleDetailView.as_view(), name='entry-detail'),
]

Django page update without refresh, page only displays base.html

I have a small Django project consisting of one app. I am very very new to Django and have run into a problem. I have an app that is a webpage with a question posed and a form that must have input. Once the button is pressed to submit the form, I would like to update the page without refreshing. I have heard AJAX is a good way to handle this but I have not been able to find any examples working with just forms.
UPDATE
after researching another users suggestions I have made some progress implementing ajax to display my form submission text. The problem is now that when navigating to the app page it displays just raw html. I am not sure why.
My Forms
from django import forms
from . import models
class AnswerForm(forms.Form):
answer = forms.CharField(label='Answer', required=True, max_length=500)
def save(self):
answer_instance = models.Answer()
answer_instance.answer_txt = self.cleaned_data["answer"]
answer_instance.save()
return answer_instance
My Models
from django.db import models
from django.forms import ModelForm
class Riddle(models.Model):
riddle_txt = models.CharField(max_length=900)
def __str__(self):
return self.riddle_txt
class Answer(models.Model):
answer_txt = models.CharField(max_length=900)
def __str__(self):
return self.answer_txt
My Views
from django.http import JsonResponse
from django.shortcuts import get_object_or_404, render
from django.template import loader
from .models import Riddle, Answer
from . import forms
# Create your views here.
def index(request):
form = forms.AnswerForm()
response_data = {} #new line
if request.method == "POST":
form = forms.AnswerForm(request.POST)
if form.is_valid():
form.save()
form = forms.AnswerForm()
response_data['text'] = form.answer_txt #new line
else:
form = forms.AnswerForm()
riddle_list = Riddle.objects.all()
answer_list = Answer.objects.all()
form = forms.AnswerForm()
template = loader.get_template('CricksRiddles/index.html')
context = {
'riddle_list': riddle_list,
'form': form,
'answer_list': answer_list,
}
#form_answer = request.POST['_form']
return render(request, 'CricksRiddles/index.html', context, {'json_data': json.dumps(response_data)}) #new line
My JS
$('#answer_form').on('submit', function(e){
e.preventDefault();
console.log("form submitted");
post_answer();
});
function post_answer() {
console.log("answer is posted without refresh");
console.log($('#answer_text').val());
}
and finally here is
MY Templates
{% extends 'base.html' %}
{% load static %}
{% block content%}
<body>
{% if riddle_list %}
<div class="riddle_box">
{% for riddle in riddle_list %}
<!-- -->
<p>{{ riddle.riddle_txt }}</p>
{% endfor %}
<!--
<!--{% for ans in answer_list %}-->
<li>{{ ans.answer_txt }}</li>
<!--{% endfor %}-->
</div>
<form id="answer_form" action="/" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" class="button" name="_form" value="Submit Answer">
</form>
{% else %}
<p>Out foraging for sticks and dogs.</p>
{% endif %}
</body>
{% endblock %}
{% block js_block %}
{% endblock %}
It's my understanding that the AJAX code would go in the block js_block, but again I can not find any information on using AJAX with a django form. Everything I have found has been model forms, but I do not want to use those. Thank you for any help.

Implementing views with template in django

I'm struggling to show on a webpage some model objects I created from the admin pages on my site.
I combed through the relevant django tutorial page but nothing I've tried works to show the model objects on the page.
Here is my models.py:
from django.db import models
from datetime import datetime
from datetime import timedelta
# Create your models here.
def get_deadline():
return datetime.today() + timedelta(days=3)
class JobPost(models.Model):
created_at = models.DateTimeField(auto_now_add=True, blank=True)
deadline = models.DateField(default=get_deadline)
wordcount = models.IntegerField()
jobtaken = models.BooleanField(default=False)
# client = models.User.username
class Meta:
ordering = (
# ("jobtaken"),
("-created_at"),
)
def publish(self):
self.pub_date = timezone.now()
self.save()
def __str__(self):
return "Job #{}".format(self.pk)`
views.py:
from django.shortcuts import render
from django.views.generic import TemplateView
#from django.contrib.auth.decorators import staff_member_required
from .models import JobPost
from django.utils import timezone
# Create your views here.
# #staff_member_required()
# class JobBoardView(TemplateView):
# template_name = "jobs.html"
# posts = JobPost.objects.filter(published_date__lte=timezone.now()).order_by('pub_date')
#changed published_date to pub_date in .models
def jobs(request):
#posts = JobPost.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
latest_post_list = JobPost.objects.order_by('-pub_date')
context = {
'deadline': deadline,
'created_at': created_at,
'wordcount':wordcount,
'jobtaken':jobtaken,
'JobPost':JobPost,
'latest_post_list':latest_post_list,
}
return render(request, 'jobs.html', context=context)
urls.py:
from django.contrib import admin
from django.urls import path, re_path, include
from django.conf.urls import url
from django.contrib.auth import views as auth_views
from jobboard import views
from login import views
urlpatterns = [
path('admin/', admin.site.urls),
#re_path(r'^login/$', auth_views.login(template_name = 'accounts/login.html'), name='login'),
re_path(r'^signup/$', views.signup, name='signup'),
path('login/', include('login.urls')),
path('', views.index, name='index'),
path('accounts/', include('django.contrib.auth.urls')),
path('users/', include('users.urls')),
path('users/', include('django.contrib.auth.urls')),
path('jobs/', views.jobs, name='jobs')
]
Here is my template(jobs.html):
{% extends "base.html" %}
{% block content %}
{% if latest_post_list %}
<ul>
{% for post in latest_post_list %}
<li>{{ JobPost }}</li>
{% endfor %}
</ul>
{% else %}
<p>No posts are available.</p>
{% endif %}
{% endblock content %}
I tried various templates, including some really simple ones to test, e.g.
{% if latest_post_list %}
<p>hello</p>
{% else %}
<p>No posts are available.</p>
{% endif %}
but everything I try returns the 'else' part of the if statement. Nothing will show the objects on the webpage.
You have a made a few mistakes which I will list below:
Your query method is wrong. It should be:
latest_post_list = JobPost.objects.all().order_by('-pub_date')
or
latest_post_list = JobPost.objects.filter(something=something).order_by('-pub_date')
2. latest_post_list is not an object, it is a query of JobPost objects. If you wish to iterate them in the template, you can just pass it to the template and do the iteration from the query. However,
context = {
'deadline': deadline, # you cannot access deadline (which deadline?)
'created_at': created_at, # same as above
'wordcount':wordcount, # same as above
'jobtaken':jobtaken, # same as above
'JobPost':JobPost, # You are sending the class to the template which is wrong
'latest_post_list':latest_post_list, # the only thing you need!
}
If you wish to loop through the objects of the query in the back-end, you have to do the following:
for post in latest_post_list:
print(post.deadline) # will print the deadline of each JobPost one by one
If you wish to loop through the objects of the query and display them in the template, you have to do this:
{% for post in latest_post_list %}
<p>{{ post.deadline }} - {{ post.created_at }}</p>
{% empty %}
<p>There is no post yet!</p>
{% endfor %}
There is no need to user if in the backend or use {{ JobPost }}. if the query is empty, the {% empty %} will be effective.
RoboBear was correct, it was a name collision in the urls.py file. This fixed the error:
change to from jobboard import views as job_views and change the url line to path('jobs/', job_views.jobs, name='jobs').
Changing this raised exceptions in the views.py file for all the context dictionary entries except for
context = {
'latest_post_list':latest_post_list,
}
as Ramtin suggested.
Then I changed the template to
<ul>
{% for post in latest_post_list %}
<li>{{ post }}</li>
</ul>
{% empty %}
<p>No posts are available.</p>
{% endfor %}
as Ramtin suggested.

Django:Profiles under auth.Group where auth.Group is used as foreign key in the app model

I want to display the dashboards which are under the group of logged in user, and I already have logged in user information and group-name of that user
so far my views.py is
def custom_login(request):
if request.user.is_authenticated():
return HttpResponseRedirect('dashboards')
return login(request, 'login.html', authentication_form=LoginForm)
def custom_logout(request):
return logout(request, next_page='/')
def user(request):
context = {'user': request.user, 'groups': request.user.groups.all()}
return render_to_response('registration/dashboards.html', context, context_instance=RequestContext(request))
dashboard.html is like
{% extends "base.html" %}
{% block content %}
{% if user.is_authenticated %}
<p>Welcome, {{ request.user.get_username }}. <br/>
{% else %}
<p>Welcome, new user. Please log in.</p>
{% endif %}
<ul>
{% for group in groups %}
<li>
and you belongs to <strong>{{ group.name }}<strong> -
{% endfor %}
</li>
</ul>
{% endblock %}
forms.py looks like
from django import forms
from django.contrib.auth.models import User
from django.forms import ModelForm
#from mhawk.models import Dashboard
class LoginForm(forms.Form):
username = forms.CharField(label=(u'User Name'))
password = forms.CharField(label=(u'Password'), widget=forms.PasswordInput(render_value=False))
and my models.py is
from django.db import models
from django.contrib.auth.models import Group, User
from django.utils import timezone
import datetime
class Dashboard(models.Model):
d_name = models.CharField(max_length=200)
d_description = models.CharField(max_length=200)
d_url = models.CharField(max_length=200)
d_status = models.CharField(max_length=200)
owner = models.ForeignKey(Group)
def __str__(self):return self.d_name
and urls.py is
from django.conf.urls import patterns, include, url
from django.contrib import admin
from drinker import views, models
from django.contrib.auth.models import User
urlpatterns = patterns('',
url(r'^admin/', include(admin.site.urls)),
url(r'^login/$', 'django.contrib.auth.views.login',),
url(r'^logout/$', 'django.contrib.auth.views.logout'),
url(r'^dashboards/$', 'mhawk.views.user'),
)
as I am able to display the logged in username, in the same way I want to display his group and the dashboards which are under that group, thank you. Looking forward for help.
Can you not just do something like this:
def user(request):
user_groups = request.user.groups.all()
if request.user.is_anonymous():
user_groups = []
user_dashboards = Dashboard.objects.filter(owner__in=user_groups)
context = {
'user': request.user,
'user_groups': user_groups,
'user_dashboards': user_dashboards,
}
[...]
In your template, you need to do something like this...
{% extends "base.html" %}
{% block content %}
{% if user.is_authenticated %}
<p>Welcome, {{ request.user.get_username }}. <br/>
{% else %}
<p>Welcome, new user. Please log in.</p>
{% endif %}
<p></p>
<p>And you belongs to: </p>
<ul>
{% for group in user_groups %}
<li>
<strong>{{ group.name }}<strong> -
</li>
{% endfor %}
</ul>
{% endblock %}
Learn more about Django templating:
https://docs.djangoproject.com/en/1.7/ref/templates/builtins/#for