How do I add paginator to thid django code? - django

I have a system where users can view complaints they have registered on one page. But the problem is that only four complaints can be viewed at a time on the page. How can I add pageinator to the code so that the next four complaints can be viewed on the other page in the correct format and template:
views.py:
def History(request):
complaint_data = Complaint.objects.filter(user=request.user)
context = { 'complaint':complaint_data }
return render(request, 'myHistory.html', context)
template:
<!-- Middle Container -->
<div class="col-lg middle middle-complaint-con">
<i class="fas fa-folder-open fa-4x comp-folder-icon"></i>
<h1 class="all-comp">My Complaints</h1>
<p class="all-comp-txt">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
{%for c in complaint %}
<a href="{% url 'Complaint' c.pk %}" style="color:black;">
<div class="container comp-con-{{forloop.counter0}}">
<p style="color: #D37A19; margin-left: -130px; margin-top: -5px;">Report number:</p>
<p class="history-level-1">{{c.reportnumber}}</p>
<p class="comp-title-1">{{c.event_type}}</p>
<p class="comp-sub-1">{{c.event_text|truncatechars:85}}</p>
</div>
</a> {%endfor%}
</div>
css:
enter code h.comp-con-0 {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
padding: 11px 8px;
position: absolute;
width: 300px;
height: 140px;
left: 160px;
top: 190px;
background: #FFEEDB;
box-shadow: 1px 1px 2px rgb(0 0 0 / 25%);
border-radius: 10px;
}
.comp-con-1 {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
padding: 10px;
position: absolute;
width: 300px;
height: 140px;
left: 160px;
top: 400px;
background: #FFEEDB;
box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.25);
border-radius: 10px;
}
.comp-con-2 {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
padding: 8px;
position: absolute;
width: 300px;
height: 140px;
left: 610px;
top: 190px;
background: #FFEEDB;
box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.25);
border-radius: 10px;
}
.comp-con-3 {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
padding: 10px 9px;
position: absolute;
width: 300px;
height: 140px;
left: 610px;
top: 400px;
background: #FFEEDB;
box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.25);
border-radius: 10px;
}
I basically four css cards for four complaints and have a for.loopcounter to count the complaints in the html. How can I set the forloopcounter back to zero when the page changes to a new one. More importantly how do I add pagination to this?

For Pagination You Should Consider Django Documentation https://docs.djangoproject.com/en/3.2/topics/pagination/
from django.core.paginator import Paginator
def pagination_complaint(request, page_no):
complaint_data_paginator = Paginator(complaint_data, 4)
paginator_obj = complaint_data_paginator.get_page(page_no)
context = {'complaint':paginator_obj}
return render(request, "<your-app-name>/ajax_complaint.html", context)
Create a new template in your app as ajax_complaint.html
{%for c in complaint %}
<a href="{% url 'Complaint' c.pk %}" style="color:black;">
<div class="container comp-con-{{forloop.counter0}}">
<p style="color: #D37A19; margin-left: -130px; margin-top: -5px;">Report number:</p>
<p class="history-level-1">{{c.reportnumber}}</p>
<p class="comp-title-1">{{c.event_type}}</p>
<p class="comp-sub-1">{{c.event_text|truncatechars:85}}</p>
</div>
</a> {%endfor%}
create a new URL in urls.py for getting pagination!
path('<int:page_no>/', pagination_complaint)
now in your first template you have to add the ajax!
For adding data in the template add a new div with id="items" (it can be anything but I am using it)
Now I am going to use jQuery here! so make sure to import it in the template!
items = document.getElementsById("items");
$.ajax(
{
type: "GET",
URL: "<your pagination URL>/<page_no>/",
success: function (response) {
items.innerHTML = items.innerHTML + response
}
})

Related

How to upload images with AJAX in DJANGO

/* Add property modal */
.add-property {
position: relative;
width: 60rem;
height: 35rem;
left: 50%;
-ms-transform: translateX(-50%);
transform: translateX(-50%);
border-radius: 15px;
}
.modal-title {
position: relative;
left: 50%;
-ms-transform: translateX(-50%);
transform: translateX(-50%);
}
.close {
background-color: transparent;
border: none;
}
#footer-btn {
position: relative;
left: 50%;
-ms-transform: translateX(-50%);
transform: translateX(-50%);
border: 0.1em solid black;
border-radius: 10px;
width: 5em;
height: 2.5em;
font-weight: 600;
margin-bottom: 1.2em;
}
.add-prop {
background-color: #3498db;
color: white;
}
.add-prop:hover {
background-color: rgb(12, 65, 180);
}
.add-inpt {
outline: none;
border-width: 0 0 0.17em;
border-color: black;
border-radius: 5px;
width: 15em;
height: 2em;
text-align: center;
}
.prop-info-row {
height: 15em;
position: relative;
top: 50%;
-ms-transform: translateY(-50%);
transform: translateY(-50%);
}
.prop-info-col {
height: 2em;
}
.add-inpt::placeholder {
text-align: center;
}
.main-add-row {
width: 50rem;
height: 26rem;
border-bottom: 1px solid rgba(0, 0, 0, 0.26);
}
#property-types {
background-color: white;
height: 2.5em;
width: 13em;
border-radius: 5px;
}
/* SIDE NAV INSIDE ADD PROPERTY MODAL */
.side-nav,
.nav-menu {
height: 100%;
}
.side-nav .nav-menu {
list-style: none;
padding: 40px 0;
width: 13em;
background-color: #3498db;
}
.side-nav .nav-item {
position: relative;
padding: 0.7em 1.5em;
position: relative;
top: 42%;
-ms-transform: translateY(-50%);
transform: translateY(-50%);
}
.nav-item.active {
background-color: #fff;
box-shadow: 0px -3px rgba(0, 0, 0, 0.2), 0px 3px rgba(0, 0, 0, 0.2);
}
.nav-item.active a {
color: #2980b9;
}
.nav-item a {
text-decoration: none;
color: #fff;
}
.menu-text {
padding: 0 20px;
}
.side-nav .nav-item.active::before {
content: "";
position: absolute;
background-color: transparent;
bottom: 100%;
right: 0;
height: 150%;
width: 20px;
border-bottom-right-radius: 25px;
box-shadow: 0 20px 0 0 #fff;
}
.side-nav .nav-item.active::after {
content: "";
position: absolute;
background-color: transparent;
top: 100%;
right: 0;
height: 150%;
width: 20px;
border-top-right-radius: 25px;
box-shadow: 0 -20px 0 0 #fff;
}
/* UPLOAD IMAGE STYLE */
:root {
--clr-white: rgb(255, 255, 255);
--clr-black: rgb(0, 0, 0);
--clr-light: rgb(245, 248, 255);
--clr-light-gray: rgb(196, 195, 196);
--clr-blue: rgb(63, 134, 255);
--clr-light-blue: rgb(171, 202, 255);
}
/* End General Styles */
/* Upload Area */
.upload-area {
width: 100%;
max-width: 25rem;
background-color: var(--clr-white);
box-shadow: 0 5px 10px rgb(218, 229, 255);
border: 2px solid var(--clr-light-blue);
border-radius: 24px;
padding: 1rem 1.875rem 0rem 1.875rem;
margin: 0.625rem;
text-align: center;
}
/* Header */
.upload-area__title {
font-size: 1.8rem;
font-weight: 500;
margin-bottom: 0.3125rem;
}
.upload-area__paragraph {
font-size: 0.9375rem;
color: var(--clr-light-gray);
margin-top: 0;
}
.upload-area__tooltip {
position: relative;
color: var(--clr-light-blue);
cursor: pointer;
transition: color 300ms ease-in-out;
}
.upload-area__tooltip:hover {
color: var(--clr-blue);
}
.upload-area__tooltip-data {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -125%);
min-width: max-content;
background-color: var(--clr-white);
color: var(--clr-blue);
border: 1px solid var(--clr-light-blue);
padding: 0.625rem 1.25rem;
font-weight: 500;
opacity: 0;
visibility: hidden;
transition: none 300ms ease-in-out;
transition-property: opacity, visibility;
}
.upload-area__tooltip:hover .upload-area__tooltip-data {
opacity: 1;
visibility: visible;
}
/* Drop Zoon */
.upload-area__drop-zoon {
position: relative;
height: 13.8rem;
/* 180px */
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
border: 2px dashed var(--clr-light-blue);
border-radius: 15px;
margin-top: 1.1rem;
cursor: pointer;
transition: border-color 300ms ease-in-out;
}
.upload-area__drop-zoon:hover {
border-color: var(--clr-blue);
}
.drop-zoon__icon {
display: flex;
font-size: 3.75rem;
color: var(--clr-blue);
transition: opacity 300ms ease-in-out;
}
.drop-zoon__paragraph {
font-size: 0.9375rem;
color: var(--clr-light-gray);
margin: 0;
margin-top: 0.625rem;
transition: opacity 300ms ease-in-out;
}
.drop-zoon:hover .drop-zoon__icon,
.drop-zoon:hover .drop-zoon__paragraph {
opacity: 0.7;
}
.drop-zoon__loading-text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: none;
color: var(--clr-light-blue);
z-index: 10;
}
.drop-zoon__preview-image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: contain;
padding: 0.3125rem;
border-radius: 10px;
display: none;
z-index: 1000;
transition: opacity 300ms ease-in-out;
}
.drop-zoon:hover .drop-zoon__preview-image {
opacity: 0.8;
}
.drop-zoon__file-input {
display: none;
}
/* (drop-zoon--over) Modifier Class */
.drop-zoon--over {
border-color: var(--clr-blue);
}
.drop-zoon--over .drop-zoon__icon,
.drop-zoon--over .drop-zoon__paragraph {
opacity: 0.7;
}
/* (drop-zoon--over) Modifier Class */
.drop-zoon--Uploaded .drop-zoon__icon,
.drop-zoon--Uploaded .drop-zoon__paragraph {
display: none;
}
/* File Details Area */
.upload-area__file-details {
height: 0;
visibility: hidden;
opacity: 0;
text-align: left;
transition: none 500ms ease-in-out;
transition-property: opacity, visibility;
transition-delay: 500ms;
}
/* (duploaded-file--open) Modifier Class */
.file-details--open {
height: auto;
visibility: visible;
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
<button data-bs-toggle="modal" data-bs-target="#ModalAddProperty" class="add-more" id="add-property">Add
Property</button>
<form action="" enctype="multipart/form-data" method="POST" id="id_ajax_upload_form">
{% csrf_token %}
<div class="modal fade" id="ModalAddProperty" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content add-property">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLongTitle">Add Property</h5>
<button type="button" class="close" data-bs-dismiss="modal" aria-label="Close">
<i class="fas fa-times"></i>
</button>
</div>
<div class="modal-body" style="padding: 0;">
<div class="row g-0 main-add-row">
<div class="col-sm-3" style="padding: 0;">
<nav class="side-nav">
<ul class="nav-menu">
<li class="nav-item active" id="img-nav-link">
<a href="#">
<i class="fa-solid fa-file-arrow-up"></i>
<span class="menu-text">Upload Image</span>
</a>
</li>
<li class="nav-item" id="prop-info-nav-link">
<a href="#">
<i class="fa-solid fa-house-chimney-crack"></i>
<span class="menu-text">Propery Info</span>
</a>
</li>
</ul>
</nav>
</div>
<div class="col-md-9 d-flex justify-content-center" id="toggle-content-add-modal">
<!-- UPLOAD IMAGE SECTION START -->
<div id="uploadArea" class="upload-area" data-target="img-nav-link">
<!-- Header -->
<div class="upload-area__header">
<h1 class="upload-area__title">Upload your file</h1>
<p class="upload-area__paragraph">
File should be an image
<strong class="upload-area__tooltip">
Like
<span class="upload-area__tooltip-data"></span>
<!-- Data Will Come From Js -->
</strong>
</p>
</div>
<!-- End Header -->
<!-- Drop Zoon -->
<div id="dropZoon" class="upload-area__drop-zoon drop-zoon">
<span class="drop-zoon__icon">
<i class='bx bxs-file-image'></i>
</span>
<p class="drop-zoon__paragraph">Drop your file here or Click to browse</p>
<span id="loadingText" class="drop-zoon__loading-text">Please Wait</span>
<img src="" alt="Preview Image" id="previewImage" class="drop-zoon__preview-image" draggable="false">
<input type="file" id="fileInput-single" class="drop-zoon__file-input" accept="image/*">
</div>
<!-- End Drop Zoon -->
<!-- File Details -->
<div id="fileDetails" class="upload-area__file-details file-details">
<div id="uploadedFile" class="uploaded-file">
<div class="uploaded-file__icon-container">
<i class='bx bxs-file-blank uploaded-file__icon'></i>
<span class="uploaded-file__icon-text"></span>
<!-- Data Will be Comes From Js -->
</div>
<div id="uploadedFileInfo" class="uploaded-file__info">
<span class="uploaded-file__name">Project 1</span>
<span class="uploaded-file__counter">0%</span>
</div>
</div>
</div>
<!-- End File Details -->
</div>
<!-- UPLOAD IMAGE SECTION END -->
<!-- PROPERTY INFO START -->
<div class="row g-0 justify-content-center prop-info-row" data-target="prop-info-nav-link" style="display: none;">
<div class="col-md-8 prop-info-col">
<p style="font-weight: 600;">Property Type</p>
</div>
<div class="col-md-8 d-flex justify-content-center prop-info-col">
<select name="property-types" id="property-types">
<option value="volvo">Tenament</option>
<option value="saab">Car</option>
<option value="opel" selected>Helicopter</option>
<option value="audi">Space Shuttle</option>
</select>
<div class="input-group mb-3 ms-3">
<span class="input-group-text" id="basic-addon1">OR</span>
<input type="text" class="form-control" id="new-prop-type" placeholder="Enter a new type" aria-label="Property-Type" aria-describedby="basic-addon1" autocomplete="off">
</div>
</div>
<div class="col-md-8 d-flex justify-content-center prop-info-col mt-5">
<input type="text" id="prop-name" class="add-inpt" placeholder="Property Name" autocomplete="off">
</div>
<div class="col-md-8 d-flex justify-content-center prop-info-col mt-3">
<input type="text" id="prop-address" class="add-inpt" placeholder="Property Address" autocomplete="off">
</div>
</div>
<!-- PROPERTY INFO END -->
</div>
</div>
</div>
<div class="modal-ftr">
<button type="submit" class="add-prop" id="footer-btn" data-bs-dismiss="modal">Add</button>
</div>
</div>
</div>
</div>
</form>
I have been using AJAX recently with DJANGO to send text data. It has been working smoothly and feels an easy method. But I cant understand and there no proper resource to learn to send images with AJAX and save to Django Database.
HTML:
<input type="file" id="fileInput-single" class="drop-zoon__file-input" accept="image/*">
JS:
$(".add-prop").click(function() {
var data = new FormData();
data.append("image", $("#fileInput-single")[0].files[0])
data.append("csrfmiddlewaretoken", $("input[name=csrfmiddlewaretoken]").val())
$.ajax({
method: "POST",
url: "{% url 'upload-prop-images' %}",
processData: false,
contentType: false,
mimeType: "multipart/form-data",
data: data,
success: function(data) {
if (data.status == "Upload Done") {
console.log("Uploading Done successfully")
}
}
})
});
models.py
class Property(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, related_name='property_user')
prop_images = models.ImageField(upload_to="prop_images")
views.py
def uploadPropImages(request):
image = request.POST['image']
property_new = Property(user_id=request.user.id, prop_images=image)
property_new.save()
return JsonResponse({'status': 'Upload Done'})
urls.py
urlpatterns = [
path('upload-prop-images/', views.uploadPropImages, name='upload-prop-images')
]
There is one tutorial using the forms.py file but I don't want to create a forms.py file.
HTML
<form id="upload-file" enctype="multipart/form-data">
{% csrf_token %}
<input type="file" name="file">
<button type="submit" class="btn btn-success">Upload</button>
</form>
JS
$('body').on('submit','#upload-file',function(e){
e.preventDefault()
var formData = new FormData(this);
$.ajax({
url:'/url/',
type: 'POST',
data: formData,
success: function (response) {
},
error: function (response) {
},
cache: false,
contentType: false,
processData: false
});
VIEWS.py
def fileupload(request):
if request.method=="POST":
property = Property()
property.prop_images = request.FILES['file_name']
property.user = self.request.user.username
property.save()
# Can update response as per requirement.
# Can Add `Status`: Success/Failed to make it more clear.
return JsonResponse({"Message":"File Uploaded Successfully"})
return JsonResponse({"Message":""})

How to display a list on the button when hovering over button

I have a button and I want to make a name of the button disapear when you hover over it. At the same time I want the background to change and show a list on the button.
.buttons{
width: auto;
position:horizontal;
font-size: 0;
background-color: darkslategrey;
border-radius: 10px;
}
.buttons .btn-1{
display:inline-block ;
border-radius: 8px;
background-image: url("/img/teatritood.JPG");
cursor: pointer;
background-size: 100%;
border: none;
padding:none;
height: 30rem;
width: 33.3%;
font-family: 'Courier New', Courier, monospace;
color: whitesmoke;
font-display: bold;
font-size: 30px;
box-shadow: inset 80px 80px 80px darkslategrey, inset -80px -80px 80px darkslategrey;
}
.btn-1:hover{
background-image: url("/img/teatritood.JPG");
cursor: pointer;
transition-duration: 0s;
background-size: 100%;
border: none;
padding:none;
width: 30.33%;
height: 30rem;
font-size: 0px;
box-shadow: none;
box-shadow: inset 10px 10px 10px darkslategrey, inset -10px -10px 10px darkslategrey;
}
.btn-1:hover::after{
display: block;
content: attr(data-hover);
font-family: 'Courier New', Courier, monospace;
color: whitesmoke;
font-display: bold;
font-size: 38px;
transform: rotateY(180deg);
}
<pre>
<section>
<div class="buttons">
<div>
<button type="button" class=btn-1 data-hover="Uus list">Teatritööd</button>
<button type="button" class=btn-2 data-hover="Uus list">Näitused</button>
<button type="button" class=btn-3 data-hover="Uus list">Muud</button>
</div>
</div>
</section>
<div class="hidden-list">
<div>
<ul>
<ul><a>Projektid</a></ul>
<ul>Kirjeldused</ul>
<ul>Pildid</ul>
</ul>
</div>
</div>
</pre>

Flexbox template for a draggable list

I have a list of draggable items, for a responsive design :
https://codepen.io/daedrias/pen/KyPZYG
header,
footer {
background-color: #5fba7d;
padding: 1rem;
}
.container {
display: flex;
min-height: 800px;
}
.menu {
width: 15em;
background-color: #FFF8DC;
}
.content {
background-color: #fff;
border-left: 1px solid #958C4D;
flex: 1;
padding: 5px 10px;
}
.sortable-list {
width: 18.75em;
}
.row {
display: flex;
margin-bottom: 15px;
box-sizing: border-box;
}
.row>* {
display: inline-block;
border-radius: 4px;
box-sizing: border-box;
}
.left {
height: 2em;
display: flex;
cursor: move;
}
.handle {
width: 1.5em;
height: 2em;
line-height: 2em;
text-align: center;
margin-right: 0.125em;
border-radius: 4px;
}
.icon {
width: 2em;
height: 2em;
border-radius: 4px;
background-color: #c97777;
margin: 0 0.125em;
}
.stretch {
flex: 1;
border: 1px solid black;
padding: 6px 12px;
margin: 0 0.1em;
}
.trash {
width: 2em;
height: 2em;
line-height: 2em;
text-align: center;
margin-left: 0.125em;
}
.bouton-ajout {
flex: 1;
border: 1px solid black;
border-radius: 4px;
padding: 6px 12px;
margin: 0 2.2em 0 1.75em;
}
/* mobile layout */
#media (max-width: 768px) {
.sortable-list {
width: 100%;
}
.menu {
display: none;
}
}
<html>
<head>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<header>Header</header>
<div class="container">
<div class="menu">
</div>
<div class="content">
<p>asdasd</p>
<div class="sortable-list">
<div class="row">
<div class="left">
<div class="handle">=</div>
<div class="icon"></div>
</div>
<div class="stretch">
banana
</div>
<div class="trash">X</div>
</div>
<div class="row">
<div class="left">
<div class="handle">=</div>
<div class="icon"></div>
</div>
<div class="stretch">
pineapple
</div>
<div class="trash">X</div>
</div>
<div class="row">
<div class="left">
<div class="handle">=</div>
<div class="icon"></div>
</div>
<div class="stretch">
orange
</div>
<div class="trash">X</div>
</div>
<div class="bouton-ajout">
+ Add a row V
</div>
</div>
</div>
<div>
</body>
<html>
Everything is pretty much as I want it to be (as in : the positioning, not the colors of this example), but I'm not happy about the 'add' button.
I would like to know if there is a better way to handle the width of the 'Add' button,so it is the same size as the icon + label combined. For now I use margins.
Is the flex display a good solution in this case? Should I use something else like display : table?

Another drop down menu

Here is my .html file :
{% load i18n %}
<div class="customer-context-menu closed {% if customer.gender == 0 %}male{% else %}female{% endif %}">
<b class="unselectable">
{{ customer.icon }}
{{ user.get_full_name }}
</b>
<ul>
<li class="tip"></li>
<li>{% trans "Perceptions" %}</li>
<li>{% trans "Profile" %}</li>
<li>{% trans "Alerts" %}</li>
<li>{% trans "Messaging" %}</li>
<li>{% trans "Requests" %}</li>
<li>{% trans "Documents" %}</li>
<li>{% trans "Logs" %}</li>
<li class="separator"></li>
<li>{% trans "Loan" %}</li>
<li class="separator"></li>
{% if customer.phone_1 %}
<li class="phone">{{ customer.phone_1 }}</li>
{% endif %}
<li><i class="material-icons">email</i> {{ user.email }}</li>
<li><i class="material-icons">printer</i> {% trans "Print" %}</li>
</ul>
</div>
I would like it could give me the drop down menu I drew.
Here is the the result including my drawing : drawing
Could anyone have time to show me how I could do such thing here? An example of a drop down menu into another should be sufficient.
Thanks!
P.S. Please tell me if the question is unclear.
.customer-context-menu b {
display: inline-block;
border: 1px solid #ccc;
padding: 5px 14px 2px 7px;
font-size: 12px;
border-radius: 13px;
cursor: pointer;
white-space: nowrap; }
.customer-context-menu b .material-icons {
float: left;
margin: -3px 4px 0 -5px; }
.customer-context-menu .phone {
padding: 10px 10px !important;
font-size: 1.3em;
font-weight: normal; }
.customer-context-menu.female b {
border-color: #ffcbe5;
color: #ff65b1; }
.customer-context-menu.female:hover b {
background-color: #fff4f9; }
.customer-context-menu.female.open b {
background-color: #ff65b1;
color: white; }
.customer-context-menu.female.open i {
color: white; }
.customer-context-menu.female.open ul li a:hover {
color: #ff65b1; }
.customer-context-menu.female.open .separator {
background-color: #ff65b1; }
.customer-context-menu.male b {
border-color: #90bfea;
color: #3a8dda; }
.customer-context-menu.male:hover b {
background-color: #e6f0fa; }
.customer-context-menu.male.open b {
background-color: #3a8dda;
color: white; }
.customer-context-menu.male.open i {
color: white; }
.customer-context-menu.male.open ul li a:hover {
color: #3a8dda; }
.customer-context-menu.male.open .separator {
background-color: #3a8dda; }
.customer-context-menu ul {
position: absolute;
background: white;
border: 1px solid #ccc;
margin: 10px 0 0 -6px;
padding: 6px 0;
display: none;
box-shadow: 0px 5px 14px #999;
background-color: #f4f4f4 !important; }
.customer-context-menu ul li a {
display: block;
padding: 1px 10px;
min-width: 300px; }
.customer-context-menu ul li.tip:after {
top: -10px;
right: 50px;
bottom: auto;
left: auto;
border-width: 0 9px 9px;
border-color: #bbb transparent;
position: absolute;
width: 0;
display: block;
border-style: solid;
content: "";
left: 10px;
width: 0; }
.customer-context-menu.open b, .customer-context-menu.open ul {
background: #def; }
.customer-context-menu.open ul {
display: block; }
.customer-context-menu.open ul li {
border-bottom: 1px solid #eaeaea;
padding: 2px 0; }
.customer-context-menu.open ul li:last-child, .customer-context-menu.open ul li.tip, .customer-context-menu.open ul li.separator {
border: 0; }
.customer-context-menu.open ul li.separator {
padding: 4px; }
.customer-context-menu.open ul li a {
cursor: pointer; }
.customer-context-menu.open ul li a .material-icons {
color: #888;
font-size: 1.1em;
position: relative;
top: 4px;
color: inherit; }
.customer-context-menu.open ul li a:hover {
background-color: white; }
put another ul tag after the li tag where you want to get another dropdown. i guess you need some css rule after doing this

Paginate long pages in flask flask-flatpages

I'm new with python, and i'm trying to make a website using the Flask framework.
I'm using the Flask-FlatPages extension to render markdown files from a specific directory, and i would like to paginate pages. To prevent long pages and infinite scrolling, i would like to cut pages and render each page on multiple pages. I'm thinking that a simple way could be to cut on html tag like <h2>.
I'm not sure that i am clear enough, the main idea is a kind of multi-part article or a series of article.
I have only found answers about using a database and paginate query results.
I don't know whether this should be done in python/flask or in a jinja template.
Edit :
As mentionned in my comment here, i'm using this for rendering my .md files :
pages = FlatPages(app)
#app.route('/')
def index():
# Articles are pages with a publication date
articles = (p for p in pages if 'published' in p.meta)
# Show the 10 most recent articles, most recent first.
latest = sorted(articles, reverse=True,
key=lambda p: p.meta['published'])
return render_template('articles.html', articles=latest[:10])
#app.route('/<path:path>/')
def page(path):
page = pages.get_or_404(path)
template = page.meta.get('template', 'flatpage.html')
return render_template(template, page=page)
And it's this route that i think i need to modify (or the flatpage template), to paginate page.
The simplest way to do this is to enable the table of contents extension in your FLATPAGES_MARKDOWN_EXTENSIONS (alternatively, you could enable header IDs or attribute lists and maintain the TOC yourself.):
FLATPAGES_MARKDOWN_EXTENSIONS = ['markdown.extensions.toc']
Then you can use a bit of CSS to style selected elements:
h2, p {
display: none;
}
/* At some future time
you'll be able to hide the summary
using the :has pseudo selector.
For now you'll have to use some JavaScript
to listen to click events on the TOC. */
h1:has(~ h2:target), h1:has(~ h2:target) + p {
display: none;
}
h1, h1:target + p,
h2:target, h2:target + p {
display: block;
}
/* TOC styling - not relevant to whole */
ul {
border: 1px solid gray;
list-style-type: none;
margin: 0;
padding: 1em .25em;
}
li {
display: inline-block;
margin: 0;
padding: 0;
}
li::before {
color: #777;
content: ":";
display: inline-block;
margin: 0 .5em;
}
li:first-child {
margin-left: 0;
}
li:first-child::before {
content: none;
}
<ul>
<li>summary
</li>
<li>1
</li>
<li>2
</li>
</ul>
<h1 id="summary">This is my article</h1>
<p>Some introductory content
<br>With some lines
<br>in it</p>
<h2 id="first-section">First section</h2>
<p>The most interesting thing about this content? It exists.</p>
<h2 id="second-section">Second section</h2>
<p>More content, content, content, content, content.</p>
Here's what I do. First you need to limit your database request so that if you're result is 2,000 records you only want to see the first 50 records you can do something like this at the end of your query....
"order by TableName.SomeID limit " + str(int(CurrentPage) * 50 - 50) + ", 50;"
Here's more about limit and the offset: http://www.mysqltutorial.org/mysql-limit.aspx
anyway use the CurrentPage to get your offset so that on page 1 the limit will look like this limit 0, 50 - meaning give me 50 rows and start from row 0. On page 2 the limit will look like this limit 50, 50 - meaning give me 50 rows and start from row 50. Also, you'll need to keep an order by clause in there so that the results stay consistently ordered while paging.
You'll also need to run another query without the limit so you know how many pages you have in total. This query can get away with only selecting count(*). Here's how I calc total pages from that query...
# 50 for the number of results per page
TotalPages = (ResultsCount[0]['Count(*)'] // 50)
# find out if there is a remainder of results if so add one more page
if((ResultsCount[0]['Count(*)'] % 50) > 0):
TotalPages +=1
Now your jinja2 should look something like this...
{% if TotalPages > 1 and CurrentPage < 15 %}
{% for Item in range(TotalPages) %}
{% if loop.index == CurrentPage %}
<div style="border: 1px solid; border-color: #1C5F8B; width: 22px; height: 16px; text-align: center; float: left; margin: 2px; padding-top: 2px"><b>{{ loop.index }}</b></div>
{% elif loop.index < 15 %}
<a style="cursor: pointer; color: #000000" href="/class/getdata?CurrentPage={{ loop.index }}"><div style="border: 1px solid; width: 22px; height: 16px; text-align: center; float: left; margin: 2px; padding-top: 2px">{{ loop.index }}</div></a>
{% elif loop.index == 15 %}
<a style="cursor: pointer; color: #000000" href="/class/getdata?CurrentPage={{ loop.index }}"><div style="border: 1px solid; width: 28px; height: 16px; text-align: center; float: left; margin: 2px; padding-top: 2px">Next</div></a>
{% endif %}
{% endfor %}
{% elif TotalPages > 1 and (CurrentPage + 15) < TotalPages %}
{% for Item in range(15 * CurrentPage) %}
{% if loop.index0 == (CurrentPage - 15) %}
<a style="cursor: pointer; color: #000000" href="/class/getdata?CurrentPage={{ loop.index }}"><div style="border: 1px solid; width: 28px; height: 16px; text-align: center; float: left; margin: 2px; padding-top: 2px">Prev</div></a>
{% elif loop.index == CurrentPage %}
<div style="border: 1px solid; border-color: #1C5F8B; width: 22px; height: 16px; text-align: center; float: left; margin: 2px; padding-top: 2px"><b>{{ loop.index }}</b></div>
{% elif loop.index > CurrentPage and loop.index < (CurrentPage + 15) and loop.index < TotalPages %}
<a style="cursor: pointer; color: #000000" href="/class/getdata?CurrentPage={{ loop.index }}"><div style="border: 1px solid; width: 22px; height: 16px; text-align: center; float: left; margin: 2px; padding-top: 2px">{{ loop.index }}</div></a>
{% elif loop.index == (CurrentPage + 15) and loop.index < TotalPages %}
<a style="cursor: pointer; color: #000000" href="/class/getdata?CurrentPage={{ loop.index }}"><div style="border: 1px solid; width: 28px; height: 16px; text-align: center; float: left; margin: 2px; padding-top: 2px">Next</div></a>
{% elif loop.index == TotalPages and (CurrentPage + 15) > TotalPages %}
<a style="cursor: pointer; color: #000000" href="/class/getdata?CurrentPage={{ loop.index }}"><div style="border: 1px solid; width: 22px; height: 16px; text-align: center; float: left; margin: 2px; padding-top: 2px">{{ loop.index }}</div></a>
{% endif %}
{% endfor %}
{% elif TotalPages > 1 %}
{% for Item in range(15 * CurrentPage) %}
{% if (loop.index - 1) == (CurrentPage - 15) %}
<a style="cursor: pointer; color: #000000" href="/class/getdata?CurrentPage={{ loop.index }}"><div style="border: 1px solid; width: 28px; height: 16px; text-align: center; float: left; margin: 2px; padding-top: 2px">Prev</div></a>
{% elif loop.index == CurrentPage %}
<div style="border: 1px solid; border-color: #1C5F8B; width: 22px; height: 16px; text-align: center; float: left; margin: 2px; padding-top: 2px"><b>{{ loop.index }}</b></div>
{% elif loop.index > (TotalPages - 15) and loop.index < (CurrentPage + 15) and loop.index < TotalPages %}
<a style="cursor: pointer; color: #000000" href="/class/getdata?CurrentPage={{ loop.index }}"><div style="border: 1px solid; width: 22px; height: 16px; text-align: center; float: left; margin: 2px; padding-top: 2px">{{ loop.index }}</div></a>
{% elif loop.index == TotalPages and (CurrentPage + 15) > TotalPages %}
<a style="cursor: pointer; color: #000000" href="/class/getdata?CurrentPage={{ loop.index }}"><div style="border: 1px solid; width: 22px; height: 16px; text-align: center; float: left; margin: 2px; padding-top: 2px">{{ loop.index }}</div></a>
{% endif %}
{% endfor %}
{% endif %}
Hope this helps!