<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Flask on Biraj Koirala</title><link>https://birajkoirala.com.np/tags/flask/</link><description>Recent content in Flask on Biraj Koirala</description><generator>Source Themes academia (https://sourcethemes.com/academic/)</generator><language>en-us</language><copyright>Copyright &amp;copy; {year}</copyright><lastBuildDate>Wed, 01 Jun 2022 00:00:00 +0000</lastBuildDate><atom:link href="https://birajkoirala.com.np/tags/flask/index.xml" rel="self" type="application/rss+xml"/><item><title>Your first flask project.</title><link>https://birajkoirala.com.np/post/1.contact-card/</link><pubDate>Wed, 01 Jun 2022 00:00:00 +0000</pubDate><guid>https://birajkoirala.com.np/post/1.contact-card/</guid><description>&lt;p>When I started my journey in Python, the first web framework that I learned was Flask. It was a valuable tool to showcase my projects and create simple simulations and dashboards. One of the starter projects that I did was ‘Contact Card’. This project is a simple web application that allows users to generate a QR code from a text/URL.&lt;/p>
&lt;h2 id="so-what-is-a-qr-code">So, what is a QR code?&lt;/h2>
&lt;p>QR (Quick Response) codes are two-dimensional matrices that store information scattered across messy lines and chaotic geometric shapes. They come in multiple shapes, sizes, and colors and link to text, marketing campaigns, and business cards. One widespread use case is Snapcodes.&lt;/p>
&lt;div class="gallery" data-gallery-id="gallery-1757987062-3">
&lt;div class="gallery-grid">
&lt;div class="gallery-item">
&lt;img src="qr1.jpg" alt="Gallery image 1" loading="lazy" onclick="openLightbox('gallery-1757987062-3', 0 , 'qr1.jpg')">
&lt;/div>
&lt;div class="gallery-item">
&lt;img src="qr2.jpg" alt="Gallery image 2" loading="lazy" onclick="openLightbox('gallery-1757987062-3', 1 , 'qr2.jpg')">
&lt;/div>
&lt;div class="gallery-item">
&lt;img src="qr3.jpg" alt="Gallery image 3" loading="lazy" onclick="openLightbox('gallery-1757987062-3', 2 , 'qr3.jpg')">
&lt;/div>
&lt;/div>
&lt;/div>
&lt;div id="lightbox-modal-gallery-1757987062-3" class="lightbox-modal" onclick="closeLightbox('gallery-1757987062-3')">
&lt;div class="lightbox-content" onclick="event.stopPropagation()">
&lt;span class="lightbox-close" onclick="closeLightbox('gallery-1757987062-3')">&amp;times;&lt;/span>
&lt;img id="lightbox-image-gallery-1757987062-3" src="" alt="">
&lt;div class="lightbox-nav">
&lt;button class="lightbox-prev" onclick="changeImage('gallery-1757987062-3', -1)">&amp;#10094;&lt;/button>
&lt;button class="lightbox-next" onclick="changeImage('gallery-1757987062-3', 1)">&amp;#10095;&lt;/button>
&lt;/div>
&lt;div class="lightbox-counter">
&lt;span id="image-counter-gallery-1757987062-3">1 / 3&lt;/span>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;style>
.gallery {
margin: 2rem 0;
}
.gallery-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 1rem;
padding: 1rem;
}
.gallery-item {
position: relative;
overflow: hidden;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
transition: transform 0.3s ease;
height: 270px;
display: flex;
align-items: center;
justify-content: center;
background-color: #f8f9fa;
}
.gallery-item:hover {
transform: translateY(-5px);
}
.gallery-item img {
max-width: 100%;
max-height: 100%;
width: auto;
height: auto;
object-fit: contain;
display: block;
transition: transform 0.3s ease;
}
.gallery-item:hover img {
transform: scale(1.05);
}
.gallery-item a {
display: block;
text-decoration: none;
}
&lt;/style>
&lt;style>
.lightbox-modal {
display: none;
position: fixed;
z-index: 10000;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.9);
cursor: pointer;
}
.lightbox-content {
position: relative;
margin: auto;
padding: 20px;
width: 90%;
max-width: 1200px;
height: 90%;
display: flex;
align-items: center;
justify-content: center;
cursor: default;
}
.lightbox-close {
position: absolute;
top: 15px;
right: 35px;
color: white;
font-size: 40px;
font-weight: bold;
cursor: pointer;
z-index: 10001;
background: rgba(0, 0, 0, 0.7);
width: 50px;
height: 50px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
}
.lightbox-close:hover {
background: rgba(0, 0, 0, 1);
transform: scale(1.1);
}
#lightbox-image {
max-width: 100%;
max-height: 100%;
object-fit: contain;
border-radius: 8px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
}
.lightbox-nav {
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 100%;
display: flex;
justify-content: space-between;
pointer-events: none;
}
.lightbox-prev,
.lightbox-next {
background: rgba(0, 0, 0, 0.7);
color: white;
border: none;
font-size: 30px;
padding: 15px 20px;
cursor: pointer;
border-radius: 50%;
transition: all 0.3s ease;
pointer-events: all;
}
.lightbox-prev:hover,
.lightbox-next:hover {
background: rgba(0, 0, 0, 1);
transform: scale(1.1);
}
.lightbox-prev {
margin-left: 20px;
}
.lightbox-next {
margin-right: 20px;
}
.lightbox-counter {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
color: white;
background: rgba(0, 0, 0, 0.7);
padding: 10px 20px;
border-radius: 20px;
font-size: 16px;
}
.gallery-item img {
cursor: pointer;
transition: transform 0.3s ease;
}
.gallery-item img:hover {
transform: scale(1.05);
}
&lt;/style>
&lt;script>
if (typeof window.galleryData === 'undefined') {
window.galleryData = {};
window.openLightbox = function(galleryId, index, imageSrc) {
console.log('=== OPENING LIGHTBOX ===');
console.log('Gallery ID:', galleryId);
console.log('Clicked image src:', imageSrc);
console.log('Clicked image index:', index);
const currentIndex = parseInt(index);
const modal = document.getElementById(`lightbox-modal-${galleryId}`);
const lightboxImage = document.getElementById(`lightbox-image-${galleryId}`);
const imageCounter = document.getElementById(`image-counter-${galleryId}`);
const gallery = document.querySelector(`[data-gallery-id="${galleryId}"]`);
if (!gallery) {
console.log('ERROR: Gallery element not found for ID:', galleryId);
return;
}
const images = Array.from(gallery.querySelectorAll('.gallery-item img')).map(img => img.src);
console.log('Gallery element found:', gallery);
console.log('All images in this gallery:', images);
console.log('Number of images found:', images.length);
const galleryData = {
currentIndex: currentIndex,
images: images.slice()
};
if (galleryData.currentIndex &lt; 0) galleryData.currentIndex = 0;
if (galleryData.currentIndex >= images.length) galleryData.currentIndex = images.length - 1;
window.galleryData[galleryId] = galleryData;
lightboxImage.src = imageSrc;
imageCounter.textContent = `${galleryData.currentIndex + 1} / ${images.length}`;
modal.style.display = 'block';
document.body.style.overflow = 'hidden';
console.log('Stored gallery data for', galleryId, ':', window.galleryData[galleryId]);
console.log('All gallery data keys:', Object.keys(window.galleryData));
console.log('========================');
};
window.closeLightbox = function(galleryId) {
const modal = document.getElementById(`lightbox-modal-${galleryId}`);
modal.style.display = 'none';
document.body.style.overflow = 'auto';
};
window.changeImage = function(galleryId, direction) {
console.log('=== CHANGING IMAGE ===');
console.log('Gallery ID:', galleryId);
console.log('Direction:', direction);
console.log('All available gallery data keys:', Object.keys(window.galleryData));
if (!window.galleryData[galleryId]) {
console.log('ERROR: No gallery data found for:', galleryId);
console.log('Available gallery data:', window.galleryData);
return;
}
const galleryData = window.galleryData[galleryId];
console.log('Gallery data for', galleryId, ':', galleryData);
console.log('Current index before change:', galleryData.currentIndex);
console.log('Images available for this gallery:', galleryData.images);
console.log('Number of images:', galleryData.images.length);
if (!galleryData.images || galleryData.images.length === 0) {
console.log('ERROR: Gallery data is corrupted for:', galleryId);
return;
}
galleryData.currentIndex += direction;
if (galleryData.currentIndex >= galleryData.images.length) {
galleryData.currentIndex = 0;
} else if (galleryData.currentIndex &lt; 0) {
galleryData.currentIndex = galleryData.images.length - 1;
}
const lightboxImage = document.getElementById(`lightbox-image-${galleryId}`);
const imageCounter = document.getElementById(`image-counter-${galleryId}`);
console.log('New index after change:', galleryData.currentIndex);
console.log('New image src:', galleryData.images[galleryData.currentIndex]);
console.log('Lightbox image element found:', lightboxImage);
console.log('Image counter element found:', imageCounter);
if (lightboxImage &amp;&amp; imageCounter) {
lightboxImage.src = galleryData.images[galleryData.currentIndex];
imageCounter.textContent = `${galleryData.currentIndex + 1} / ${galleryData.images.length}`;
console.log('Image updated successfully to:', galleryData.images[galleryData.currentIndex]);
} else {
console.log('ERROR: Could not find lightbox elements for gallery:', galleryId);
}
console.log('=======================');
};
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape' || e.keyCode === 27) {
const openModals = document.querySelectorAll('.lightbox-modal[style*="block"]');
openModals.forEach(modal => {
modal.style.display = 'none';
document.body.style.overflow = 'auto';
});
}
});
document.addEventListener('keydown', function(e) {
const openModal = document.querySelector('.lightbox-modal[style*="block"]');
if (openModal) {
const galleryId = openModal.id.replace('lightbox-modal-', '');
if (e.key === 'ArrowLeft' || e.keyCode === 37) {
window.changeImage(galleryId, -1);
} else if (e.key === 'ArrowRight' || e.keyCode === 39) {
window.changeImage(galleryId, 1);
}
}
});
}
&lt;/script>
&lt;p>&lt;!-- raw HTML omitted -->The images above show that QR code can be of different types,sizes and color.&lt;!-- raw HTML omitted -->&lt;/p>
&lt;h3 id="and-why-is-the-project-named-contact-card">And why is the project named Contact Card?&lt;/h3>
&lt;p>This project explores a single use-case of QR code - creating your contact information. For example, you may store simple textual details about yourself or add a link that redirects to your bio in LinkedIn/Twitter/Facebook/personal website.&lt;/p>
&lt;p>Here, I would like to explain three features of flask . For the complete code please visit &lt;a href="https://github.com/biraj094/contact_card" target="_blank" rel="noopener noreferrer" class="">
Github
&lt;/a> .&lt;/p>
&lt;h3 id="1-using-dynamic-routes">1. Using dynamic routes&lt;/h3>
&lt;p>Dynamic routing is an approach to selecting paths based on real-time changes. For example, say you are creating a route &lt;!-- raw HTML omitted -->/profile&lt;!-- raw HTML omitted -->, to show the profile of 50 students in a class. However, the same route can show the personalized profile of each student if we associate a student to an id. We can do so by making our route dynamic.&lt;/p>
&lt;pre tabindex="0">&lt;code>@app.route(’/profile/&amp;lt;int:id&amp;gt;’,methods= [’GET’])
def profile(id):
# Create different profile for different user.
&lt;/code>&lt;/pre>&lt;p>Notice how the &lt;!-- raw HTML omitted -->id&lt;!-- raw HTML omitted --> parameter is passed to the function &lt;!-- raw HTML omitted -->profile&lt;!-- raw HTML omitted -->, implying that personalized information can be returned to the same route.
Thus, &lt;code>www.example.com/profile/1&lt;/code> points to a personalized page for student A, and &lt;code>www.example.com/profile/2&lt;/code> points to a personalized page for student B, and so on.&lt;/p>
&lt;p>A similar approach was used to pass the URL that generated the QR code. However, Flask throws an error if the text or the URL contains backslash ‘/’. A workaround for this was &lt;!-- raw HTML omitted -->/display/path:URL&lt;!-- raw HTML omitted -->. Specifying the URL as &lt;!-- raw HTML omitted -->path&lt;!-- raw HTML omitted --> allowed us to send any URL type to another page without any error.&lt;/p>
&lt;pre tabindex="0">&lt;code>@app.route(’/display/&amp;lt;path:url&amp;gt;’,methods=[’POST’,’GET’])
&lt;/code>&lt;/pre>&lt;!-- raw HTML omitted -->
&lt;hr>
&lt;h3 id="2-returning-file-object">2. Returning file object&lt;/h3>
&lt;p>It is not necessary to render a template for each route. You can return any file you wish using &lt;!-- raw HTML omitted -->send_file&lt;!-- raw HTML omitted -->. I have added a feature to download the QR image as an attachment when &lt;!-- raw HTML omitted -->/download&lt;!-- raw HTML omitted --> route is called for this project. The name and type of the file must be added.&lt;/p>
&lt;pre tabindex="0">&lt;code>return send_file(str_io,
attachment_filename=”my_image.png”,
mimetype=’image/png’,
as_attachment=True)
&lt;/code>&lt;/pre>&lt;p>The type of file you wish to return is specified in the mime-type attribute. The image, “my_image.png” is converted to a string object. Since the &lt;!-- raw HTML omitted -->as_attachment&lt;!-- raw HTML omitted --> is set to &lt;!-- raw HTML omitted -->True&lt;!-- raw HTML omitted -->, the file is downloaded.&lt;/p>
&lt;hr>
&lt;h3 id="3-temporary-storage-of-files">3. Temporary storage of files&lt;/h3>
&lt;pre tabindex="0">&lt;code> with NamedTemporaryFile(delete=True) as tmp:
qrimage.save(tmp.name)
str_io = io.BytesIO(tmp.read())
&lt;/code>&lt;/pre>&lt;p>&lt;!-- raw HTML omitted -->NamedTemporaryFile&lt;!-- raw HTML omitted --> is used to return a file-type object which can be stored temporarily. For example, the QR object is saved using a temporary name and is converted to an IO object. Since I just wanted to display the picture and not store it in the project directory, I set the &lt;!-- raw HTML omitted -->delete&lt;!-- raw HTML omitted --> parameter to &lt;!-- raw HTML omitted -->True&lt;!-- raw HTML omitted --> .The &lt;!-- raw HTML omitted -->BytesIO&lt;!-- raw HTML omitted --> object is just a chunk of memory that behaves like a file.&lt;/p>
&lt;hr>
&lt;a class="btn btn-primary "
href="https://github.com/biraj094/contact_card"
target="_blank">Visit the Project on GitHub
&lt;/a></description></item></channel></rss>