I try to pass information to an html template from a view function. Every time I try to call the variable from the html template it doesn't show anything.
Here is my configure_peplink.html:
{% extends "base_generic.html" %}
{% block content %}
<h1>Configure Peplink</h1>
<p>Configure a Peplink router from the web. This was designed by <em>Valorence LLC</em></p>
{% if peplink %}
<p>Serial Number: {{ peplink.serial_number }}</p>
<p>IP Address: {{ peplink.ip_address }}</p>
<p>Mac Address: {{ peplink.mac_address }}</p>
<p>Name: {{ peplink.name }}</p>
{% else %}
<p>No Data Found Off Device</p>
{% endif %}
{% endblock %}
Here is the view function configure_peplink:
def configure_peplink(request, peplink):
selected_peplink = PeplinkDevice.objects.get(serial_number=peplink)
print(selected_peplink.ip_address)
print(selected_peplink.serial_number)
print(selected_peplink.mac_address)
context = {
'peplink': selected_peplink
}
return render(request, 'configure_peplink.html', context=context)
Here is the url line to call the view:
re_path(r'^configurepeplink/(?P<peplink>.*)/$', views.configure_peplink, name='configurepeplink')
I've tested to make sure that the context has data in it (as seen with the print statements). Even though the context variable has data and is getting past the if statement in the html template it still doesn't display any data. I have tried clearing my cache on the browser and restarting all my services (django, celery, redis-server).
Here is a picture of the webpage:
The peplink variable (which is being used by the regex url and the view function) seems to be causing the problem. Change the name of the key or change the regex url variable for this to work. To get this to work by changing the key name in the view function do the following in the view function:
def configure_peplink(request, peplink):
selected_peplink = PeplinkDevice.objects.get(serial_number=peplink)
print(selected_peplink.ip_address)
print(selected_peplink.serial_number)
print(selected_peplink.mac_address)
context = {
'selected_peplink': selected_peplink
}
return render(request, 'configure_peplink.html', context=context)
Then change the html template to the following:
{% extends "base_generic.html" %}
{% block content %}
<h1>Configure Peplink</h1>
<p>Configure a Peplink router from the web. This was designed by <em>Valorence LLC</em></p>
{% if selected_peplink %}
<p>Serial Number: {{ selected_peplink.serial_number }}</p>
<p>IP Address: {{ selected_peplink.ip_address }}</p>
<p>Mac Address: {{ selected_peplink.mac_address }}</p>
<p>Name: {{ selected_peplink.name }}</p>
{% else %}
<p>No Data Found Off Device</p>
{% endif %}
{% endblock %}
I am doing a flask tutorial here, and in the end, keep developing section it says to implement a search box that filters the index page by name,after trail and error I came up to displaying the search page, but still I don't get the results back of my search.
Here is my Search HTML:
<form method="GET" action="{{ url_for('blog.search') }}">
<input type="text" placeholder="Search by" name="q" value="{{ request.args.get('q', '') }}">
<button type="submit">Go</button>
</form>
Here is my route
from flask import request
#bp.route('/search', methods=['GET','POST'])
def search():
db = get_db()
query = request.args.get('q')
posts = db.execute(
"SELECT title, body FROM post WHERE body LIKE ? ",
('%'+ query +'%',)).fetchall()
return render_template('blog/search.html', posts=posts )
Here is my search 'blog/search.html' template
<ul>
{% for post in posts %}
<li> {{ post['title'] }} </li>
<li> {{ post['body'] }} </li>
{% endfor %}
</ul>
Is there a problem in my route or the sql query?
or is there a better way to implement a search, in flask without any extensions, thanks.
I have figured it out.
it was a mistake on my end on the 'blog/search.html' template below is my working code
my route for search:
#bp.route('/search', methods=['GET','POST'])
def search():
db = get_db()
query = request.args.get('q')
posts = db.execute(
"select id, title from post where title LIKE ? ",
('%'+ query+'%',)
).fetchall()
return render_template('blog/search.html', posts=posts)
note: this route only checks for the title of my db
my new 'blog/search.html' template:
{% if posts %}
<ul>
{% for post in posts %}
<li>{{ post[1] }}</li>
{% endfor %}
</ul>
{% else %}
<p>no entries</p>
{% endif %}
note: '{{ url_for... }}' is a link used to look into details of the search
Hope this gets helpful to someone trying to implement a search in this tutorial.
cheers :)
I made a form to reset password, when I submit the form with an empty password, the error prompt words I set in views.py didn't show up at the <span> I left in a HTML, a default Fill out this field showed instead.
*fisrt one is old password, second one is new password
In forms.py:
class PwdForm(FlaskForm):
old_pwd = PasswordField(
label="OldPassword",
validators=[
DataRequired("Please input old password")
]
)
submit = SubmitField(
"Confirm"
)
In views.py:
#admin.route("/pwd_reset/", methods=["GET", "POST"])
#admin_login_req
def pwd_reset():
form = PwdForm()
if form.validate_on_submit():
data = form.data
admin = Admin.query.filter_by(name=session["admin"]).first()
from werkzeug.security import generate_password_hash
admin.pwd = generate_password_hash(data["new_pwd"])
db.session.add(admin)
db.session.commit()
flash("ok, now use your new password to login", "ok")
redirect(url_for("admin.logout"))
return render_template("admin/pwd_reset.html", form=form)
In html:
<label for="input_pwd">{{ form.old_pwd.label }}</label>
{{ form.old_pwd }}
{% for err in form.old_pwd.errors %}
<span style="color: #ff4f1f">{{ err }}</span>
{% endfor %}
How to make my own prompt message show up
I think you mean how do you get your flash message to display? Use the following code in your base template page or in each page. See: Message Flashing
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul class="flashes">
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
I'm using the django-filter package to provide a search functionality on my List View.
Now I want to add a pagination to that view as well.
I'm trying to combine pagination to a filtered queryset, but I have no clue on how to go on.
So far, I have tried the following on views.py:
def search(request):
qs = local_url.objects.filter(global_url__id=1).all()
paginator = Paginator(qs, 25)
page = request.GET.get('page')
try:
pub = paginator.page(page)
except PageNotAnInteger:
pub = paginator.page(1)
except EmptyPage:
pub = paginator.page(paginator.num_pages)
url_filter = PublicationFilter(request.GET, queryset=qs)
return render(request, 'ingester/search_list.html', {'filter': url_filter, 'publication':pub})
This worked for me:
in my template instead of using this
<li>{{ i }}</li>
I wrote this:
{% if 'whatever_parameter_you_use_to_filter' in request.get_full_path %}
<li><a href="{{ request.get_full_path }}&page={{ i }}"{{ i }}</a></li>
{% else %}
<li>{{ i }}</li>
{% endif %}
I hope it helps :)
To use Django Filter and paginate the filtered result you can do the following:
Create a filter class for your model:
On my_project/my_app/filters.py:
import django_filters
class MyModelFilter(django_filters.FilterSet):
class Meta:
model = MyModel
# Declare all your model fields by which you will filter
# your queryset here:
fields = ['field_1', 'field_2', ...]
Every FilterSet object has a .qs property which contains the filtered queryset and you can even override it if you want.
We will paginate the .qs property of our MyModelFilter:
On my_project/my_app/views.py:
from . import filters
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
def my_view(request):
# BTW you do not need .all() after a .filter()
# local_url.objects.filter(global_url__id=1) will do
filtered_qs = filters.MyModelFilter(
request.GET,
queryset=MyModel.objects.all()
).qs
paginator = Paginator(filtered_qs, YOUR_PAGE_SIZE)
page = request.GET.get('page')
try:
response = paginator.page(page)
except PageNotAnInteger:
response = paginator.page(1)
except EmptyPage:
response = paginator.page(paginator.num_pages)
return render(
request,
'your_template.html',
{'response': response}
)
And there you have it!
PS_1: Django filter in my experience, "plays" better with Django Rest Framework.
PS_2: If you are about to utilize DRF, I have written an example on how to use pagination in a function based view which you can easily combine with a FilterSet:
#api_view(['GET',])
def my_function_based_list_view(request):
paginator = PageNumberPagination()
filtered_set = filters.MyModelFilter(
request.GET,
queryset=MyModel.objects.all()
).qs
context = paginator.paginate_queryset(filtered_set, request)
serializer = MyModelSerializer(context, many=True)
return paginator.get_paginated_response(serializer.data)
To add to the answers, I did it with html tables too along with django-filters and Paginator. Below are my view and template files. The template tag is needed to make sure you pass the right parameters to the pagination url.
search_view.py
from django.shortcuts import render
from app.models.filters_model import ApiStatusFilter
from app.models.api_status import ApiStatus
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from datetime import datetime, timedelta
def status(request):
all_entries_ordered = ApiStatus.objects.values().order_by('-created_at')[:200]
for dictionarys in all_entries_ordered:
dictionarys
apistatus_list = ApiStatus.objects.values().order_by('-created_at')
apistatus_filter = ApiStatusFilter(request.GET, queryset=apistatus_list)
paginator = Paginator(apistatus_filter.qs, 10)
page = request.GET.get('page')
try:
dataqs = paginator.page(page)
except PageNotAnInteger:
dataqs = paginator.page(1)
except EmptyPage:
dataqs = paginator.page(paginator.num_pages)
return render(request, 'status_page_template.html', {'dictionarys': dictionarys, 'apistatus_filter': apistatus_filter, 'dataqs': dataqs, 'allobjects': apistatus_list})
status_template.html
{% load static %}
{% load my_templatetags %}
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" type="text/css" href="{% static 'css/table_styling.css' %}">
<meta charset="UTF-8">
<title>TEST</title>
</head>
<body>
<table>
<thead>
<tr>
{% for keys in dictionarys.keys %}
<th>{{ keys }}</th>
{% endfor %}
</tr>
</thead>
<form method="get">
{{ apistatus_filter.form.as_p }}
<button type="submit">Search</button>
{% for user in dataqs.object_list %}
<tr>
<td>{{ user.id }}</td>
<td>{{ user.date_time }}</td>
<td>{{ user.log }}</td>
</tr>
{% endfor %}
</form>
</tbody>
</table>
<div class="pagination">
<span>
{% if dataqs.has_previous %}
« first
previous
{% endif %}
<span class="current">
Page {{ dataqs.number }} of {{ dataqs.paginator.num_pages }}.
</span>
{% if dataqs.has_next %}
next
last »
{% endif %}
</span>
</div>
</body>
</html>
my_templatetags.py
from django import template
register = template.Library()
#register.simple_tag
def query_transform(request, **kwargs):
updated = request.GET.copy()
for k, v in kwargs.items():
if v is not None:
updated[k] = v
else:
updated.pop(k, 0)
return updated.urlencode()
It took me some time to find the DRYer and cleaner solution to fix this issue and the best one, in my opinion, is the one using template tags.
from django import template
register = template.Library()
#register.simple_tag
def relative_url(value, field_name, urlencode=None):
url = '?{}={}'.format(field_name, value)
if urlencode:
querystring = urlencode.split('&')
filtered_querystring = filter(lambda p: p.split('=')[0] != field_name, querystring)
encoded_querystring = '&'.join(filtered_querystring)
url = '{}&{}'.format(url, encoded_querystring)
return url
and in your template
{{ i }}
Source: Dealing With QueryString Parameters
The most important part here is the how you construct your URLs in the template.
you probably have
{% if pages.has_previous %}
<li>Prev</li>
{% endif %}
which is perfectly fine if you are using only it for switching between the initial paginated results.
But the tricky part is when you use the django-fitler filters, the querystring (that part after the '?') gets totally new key-values pairs, disregarding your ?page=2 or similar.
So to make pagination work with filtered results, when you click the "Next" or "Prev" button - among the key-values from django-fitler you also need to pass the &page=5 as pair.
As #stathoula mentioned, you need to check if at least one of your filter fields is already present in the querystring. If it is, then you need to use the already present key-value pairs, followed by the new &page=3 pair.
It seems very simple, but I had to done small hackish not to repeat the &page=1 over and over again within the querystring as a user is clicking trough the arrows.
In my case I'm having 'title' as a filter, so I need to check if it's already present there.
Here's a snippet of what I've made working perfectly fine for my project.
templates/pagination.html
<div class="paginator">
{% with request.get_full_path as querystring %}
<ul class="pagination nav navbar-nav">
<!-- Previous page section -->
{% if pages.has_previous %}
{% if 'title' in querystring %}
{% if 'page' in querystring %}
<li class="paginator {% if pages.number == page %}active{% endif %}">
Prev
</li>
{% else %}
<li class="paginator {% if pages.number == page %}active{% endif %}">
Prev
</li>
{% endif %}
{% else %}
<li class="paginator {% if pages.number == page %}active{% endif %}">
Prev
</li>
{% endif %}
{% endif %}
<!-- All pages section -->
{% for page in pages.paginator.page_range %}
{% if 'title' in querystring %}
{% if 'page' in querystring %}
<li class="paginator {% if pages.number == page %}active{% endif %}">
{{ page }}
</li>
{% else %}
<li class="paginator {% if pages.number == page %}active{% endif %}">
{{ page }}
</li>
{% endif %}
{% else %}
<li class="paginator {% if pages.number == page %}active{% endif %}">
{{ page }}
</li>
{% endif %}
{% endfor %}
<!-- Next page section -->
{% if pages.has_next %}
{% if 'title' in querystring %}
{% if 'page' in querystring %}
<li class="paginator {% if pages.number == page %}active{% endif %}">
Next
</li>
{% else %}
<li class="paginator {% if pages.number == page %}active{% endif %}">
Next
</li>
{% endif %}
{% else %}
<li class="paginator {% if pages.number == page %}active{% endif %}">
Next
</li>
{% endif %}
{% endif %}
</ul>
{% endwith %}
</div>
Here is the view, just in case:
app/views.py
def index(request):
condo_list = Condo.objects.all().order_by('-timestamp_created')
condo_filter = CondoFilter(request.GET, queryset=condo_list)
paginator = Paginator(condo_filter.qs, MAX_CONDOS_PER_PAGE)
page = request.GET.get('page')
try:
condos = paginator.page(page)
except PageNotAnInteger:
condos = paginator.page(1)
except EmptyPage:
condos = paginator.page(paginator.num_pages)
return render(request, 'app/index.html', {
'title': 'Home',
'condos': condos,
'page': page,
'condo_filter': condo_filter,
})
Here's a working example:
.
My approach for "remember filter/query URL parameters" for paginated results: passing the current URL parameters as a context variable:
# views.py
class PublicationFilterView(FilterView):
model = Publication
filterset_class = PublicationFilter
paginate_by = 15
def get_context_data(self, *args, **kwargs):
_request_copy = self.request.GET.copy()
parameters = _request_copy.pop('page', True) and _request_copy.urlencode()
context = super().get_context_data(*args, **kwargs)
context['parameters'] = parameters
return context
# templates/path/to/pagination.html
<a href="?page={{ page_obj.next_page_number }}&{{ parameters }}">
Next
</a>
this one works 100% with me
views.py:
def search(request):
category=Category.objects.all()
try:
qs=request.GET["qs"]
products=Product.objects.filter(Q(name__icontains=qs) |Q(details__icontains=qs) | Q(category__name__icontains=qs) | Q(branch__child__icontains=qs) | Q(manufacturer__name__icontains=qs) | Q(color__name__icontains=qs)).distinct()
print(products)
search=f"qs={qs}"
except:
search=None
and in HTML
<ul class="shop-p__pagination">
{% if products.has_provious %}
<li>
<a class="fas fa-angle-left" href="?page={{ products.previous_page_number }}&{search}"></a></li>
{% endif %}
{% for i in products.paginator.page_range %}
{% if products.number == i %}
<li class="is-active">{{i}}</li>
{% else %}
<li>{{i}}</li>
{% endif %}
{% endfor %}
{% if products.has_next %}
<li>
<a class="fas fa-angle-right" href="?page={{ products.next_page_number }}&{{search}}"></a></li>
{% endif %}
</ul>
As I understood you goal is to paginate your filtered query set. If so, you can pass "qs" property of PublicationFilter object to Paginator constructor:
def search(request):
qs = local_url.objects.filter(global_url__id=1).all()
url_filter = PublicationFilter(request.GET, queryset=qs)
paginator = Paginator(url_filter.qs, 25)
page = request.GET.get('page')
try:
pub = paginator.page(page)
except PageNotAnInteger:
pub = paginator.page(1)
except EmptyPage:
pub = paginator.page(paginator.num_pages)
url_filter = PublicationFilter(request.GET, queryset=qs)
return render(request, 'ingester/search_list.html', {'publication':pub})
url_filter.qs contains filtered QuerySet
url_filter.queryset contains non-filtered QuerySet
Simple & sweet,
use this, pip install filter-and-pagination
https://pypi.org/project/filter-and-pagination/
Implementation Step
install package by pip install filter-and-pagination
import FilterPagination by from filter_and_pagination import FilterPagination in view.py
in your function writte code as bellow standards...
queryset = FilterPagination.filter_and_pagination(request, Customer)
serialize_data = CustomerSerializer(queryset['queryset'], many=True).data
resultset = {'dataset': serialize_data, 'pagination': queryset['pagination']}
in this code Customer is Django model &
CustomerSerializer is a DRF Serializer class
in the resultset it contains dataset & pagination data, In this format (API Response) link: https://github.com/ashish1997it/filter-pagination-dj#demo
For the API request follow PostMan collection link: https://github.com/ashish1997it/filter-pagination-dj#postman in the header section it will take a parameter & request you customize as per your requirement
If you still face any difficulty then contact me :)
In get_context_data() function:
form_submitted = 'csrfmiddlewaretoken' in self.request.GET
context['cleaned_full_path'] = '{}{}'.format(
self.request.get_full_path().split('&page' if form_submitted else '?page')[0],
'&' if form_submitted else '?'
)
Then, in your template, load in something like
<a href="{{ cleaned_full_path }}page={{ page_obj.paginator.num_pages }}"
In addition to #stathoula and in response to #Benbb96, I managed to erase the additional page parameters with a regular expression, overriding the setup method in the class based view:
import re
...
class MyView(ListView):
...
def setup(self, request, *args, **kwargs) -> None:
request.GET.get("page")
request.META["QUERY_STRING"] = re.sub("(&|\?)page=(.)*", "", request.META.get("QUERY_STRING", ""))
return super().setup(request, *args, **kwargs)
Hope it helps anyone!
More info:
Request and Response Objects - Django docs
as_view() - Django docs
I am having trouble with my page redirect when deleting a users comment. below is my code. It deletes the message but gives me this error: Message matching query does not exist for Message.objects.get(id=message_id).delete().
def remove_message(request, message_id):
Message.objects.get(id=message_id).delete()
return redirect(reverse('dashboard:show'))
^ABOVE FIXED:
new issue, cannot get my delete button to show when trying to delete only the current users comments. Code below:
views.py
def remove_message(request, user_id, message_id):
user = User.objects.get(id=request.session['user_id'])
Message.objects.filter(id=message_id, user = request.user).delete()
return redirect(reverse('dashboard:show', args=user_id))
show.html
{% for message in messages%}
<div class="message">
<p class='bg-primary wall_content'><strong>{{message.messageuser.first_name}} wrote:</strong></p>
<p class='wall_content'>{{message.message}}</p>
{% if message.id == request.user %}
<a href='{% url "dashboard:remove_message" user.id message.id %}'>Delete Message</a>
{% endif %}
{% for comment in comments %}
{% if message.id == comment.message.id %}
<p class='bg-success wall_content comment'><strong>{{comment.user.first_name}} wrote:</strong></p>
<p class='wall_content comment'>{{comment.comment}}</p>
{% endif %}
{% endfor %}
Instead of get, you can use filter which returns QuerySet. Unlike the get method, the filter does not raise ObjectDoesNotExist exception, but just returns a empty queryset if there's no matching object.
Deleting empty queryset has no harm.
So you the line can be replaced with:
Message.objects.filter(id=message_id).delete()