Handling File Uploads in Different Python Frameworks

Learn how to handle file uploads in popular Python frameworks like Flask, Django, FastAPI, and Frappe. Step-by-step guide with examples. Perfect for developers!

To handle file uploads from an HTML form in your Python Frameworks, you typically handle them differently depending on the web framework you’re using (e.g., Flask, Django, FastAPI, Frappe, etc.).

Note: HTML form must include enctype="multipart/form-data".

In this article, we learn how to handle file uploads in some common Python web frameworks:

Using Flask

Design an HTML form with file field as follows,

<form action="/upload" method="post" enctype="multipart/form-data">
  <input type="file" name="myfile">
  <input type="submit">
</form>

You can get the uploaded file from the myfile field as follows,

from flask import Flask, request

app = Flask(__name__)

@app.route('/upload', methods=['POST'])
def upload_file():
    uploaded_file = request.files['myfile']
    if uploaded_file.filename != '':
        uploaded_file.save(f"./uploads/{uploaded_file.filename}")
    return "File uploaded successfully!"

Using Django

In Django, HTML form is exactly same. But, you have to add csrf_token to each form.

<form method="post" enctype="multipart/form-data">
  {% csrf_token %}
  <input type="file" name="myfile">
  <input type="submit">
</form>

You can get the file from the myfile field as follows,

from django.core.files.storage import FileSystemStorage
from django.http import HttpResponse

def upload_file(request):
    if request.method == 'POST' and request.FILES['myfile']:
        uploaded_file = request.FILES['myfile']
        fs = FileSystemStorage()
        fs.save(uploaded_file.name, uploaded_file)
        return HttpResponse('File uploaded!')
    return HttpResponse('Upload form')

Get book to learn basics of python from https://amzn.to/3FIs9cW

Using FastAPI

The HTML design file is same as the Django HTML file with csrf_token.

Backend code to get the uploaded file is as follows,

from fastapi import FastAPI, File, UploadFile
from fastapi.responses import HTMLResponse

app = FastAPI()

@app.post("/upload/")
async def upload_file(file: UploadFile = File(...)):
    contents = await file.read()
    with open(f"./uploads/{file.filename}", "wb") as f:
        f.write(contents)
    return {"filename": file.filename}

Using Frappe

In Frappe, when you submit a file from an HTML form, you can handle file uploads using its built-in frappe.utils.file_manager.save_file() method. The HTML design file for Frappe is as follows,

<form method="POST" enctype="multipart/form-data" action="/api/method/my_app.api.upload_file">
  <input type="file" name="file">
  <input type="submit" value="Upload">
</form>

In Frappe backend, you have to create whitelisted method for handling file upload as follows,

import frappe
from frappe.utils.file_manager import save_file
from frappe import _

@frappe.whitelist(allow_guest=True)  # or remove `allow_guest=True` if auth is needed
def upload_file():
    # Access the uploaded file from the request
    uploaded_file = frappe.request.files.get('file')
    
    if not uploaded_file:
        frappe.throw(_("No file uploaded"))

    # Save the file using Frappe's file manager
    saved_file = save_file(
        filename=uploaded_file.filename,
        content=uploaded_file.stream.read(),
        dt=None,  # You can pass doctype here if you want to attach it
        dn=None   # and document name
    )

    return {
        "message": "File uploaded successfully",
        "file_url": saved_file.file_url,
        "file_name": saved_file.file_name
    }

Conclusion

In above post, we learned file uploads using four different Python backed frameworks. We learned that different framework have different ways to handle file uploads.

Disclaimer: This post contains affiliate links. If you use these links to buy something, I may earn a commission at no extra cost to you.

Develop Contact Form using Livewire in Laravel

Learn how to create a responsive contact form using Livewire in Laravel. Step-by-step tutorial with validation, form submission, and real-time updates.

Developing a Contact form using Livewire in Laravel is straightforward and involves a very few key steps.

In this post, we will learn to develop contact form using Livewire component in Laravel. Follow the below steps:

Step 1: Install Livewire

To create any Livewire form, you must have Livewire installed over Laravel project. If you haven’t installed Livewire yet, you can do so via Composer:

composer require livewire/livewire

It will install Livewire package to you Laravel project.

Step 2: Create a Livewire Component

Now, we need to create a Livewire component for contact form. You can generate a Livewire component using Artisan command as follows:

php artisan make:livewire ContactForm

This will create 2 files as follows:

  • A Livewire component file at app/Http/Livewire/ContactForm.php
  • A Blade view at resources/views/livewire/contact-form.blade.php

Your contact form component is now ready to be used. But, we haven’t added any logic or any design to this component. So, if you add this component to any file, it will display blank page.

Step 3: Define the Livewire Component Logic

Open app/Http/Livewire/ContactForm.php and add all contact form related logic to the file as follows:

namespace App\Http\Livewire;

use Livewire\Component;
use App\Models\Contact;
use Illuminate\Validation\Rule;

class ContactForm extends Component
{
    public $name, $email, $message;

    protected $rules = [
        'name' => 'required|min:3',
        'email' => 'required|email',
        'message' => 'required|min:5',
    ];

    public function submit()
    {
        $this->validate();

        // Save data
        Contact::create([
            'name' => $this->name,
            'email' => $this->email,
            'message' => $this->message,
        ]);

        // Reset the form
        $this->reset(['name', 'email', 'message']);

        session()->flash('success', 'Your message has been sent!');
    }

    public function render()
    {
        return view('livewire.contact-form');
    }
}

Step 4: Create the Livewire Blade View

Open resources/views/livewire/contact-form.blade.php and update the HTML form as per your requirement. I have added my blade file design as follows:

<div>
    @if (session()->has('success'))
        <div class="p-3 mb-4 text-green-600 bg-green-200 border border-green-600 rounded">
            {{ session('success') }}
        </div>
    @endif

    <form wire:submit.prevent="submit">
        <div class="mb-4">
            <label for="name" class="block font-bold">Name:</label>
            <input type="text" id="name" wire:model="name" class="w-full p-2 border rounded">
            @error('name') <span class="text-red-600">{{ $message }}</span> @enderror
        </div>

        <div class="mb-4">
            <label for="email" class="block font-bold">Email:</label>
            <input type="email" id="email" wire:model="email" class="w-full p-2 border rounded">
            @error('email') <span class="text-red-600">{{ $message }}</span> @enderror
        </div>

        <div class="mb-4">
            <label for="message" class="block font-bold">Message:</label>
            <textarea id="message" wire:model="message" class="w-full p-2 border rounded"></textarea>
            @error('message') <span class="text-red-600">{{ $message }}</span> @enderror
        </div>

        <button type="submit" class="px-4 py-2 text-white bg-blue-600 rounded">Send</button>
    </form>
</div>

I have added some additional features like displaying success message and added error message display elements to each fields.

Step 5: Add Livewire to a Page

Now it is ready to be included to any page. You can include this component using @livewire directive provided by Livewire package. Include this Livewire component in your Blade view (e.g., resources/views/contact.blade.php):

@extends('layouts.app')

@section('content')
    <div class="container mx-auto p-4">
        <h1 class="text-xl font-bold">Contact Us</h1>
        @livewire('contact-form')
    </div>
@endsection

Still it is not visible to the page. Because, Livewire scripts and styles are missing.

Step 6: Include Livewire Scripts

You have to add Livewire scripts and styles to the layout, where you want to display any Livewire Component. You can add Livewire scripts and styles to the layout using their directives @livewireScripts and @livewireStyles respectively.

Add Livewire scripts in your layouts/app.blade.php file before the closing </body> tag of the layout file:

@livewireScripts
</body>
</html>

And add the Livewire styles in <head> tag of the layout file:

@livewireStyles

Note: If you have multiple layouts and these layouts are used to display Livewire Compoment pages, then you have to add Livewire scripts and styles in all of these layouts.

Step 7: Run Migrations and Serve the App

In component file, we have added a code to save contact form details to the database. So, If you don’t have contacts table already, create a migration for the contacts table:

php artisan make:migration create_contacts_table

Open the migration file (database/migrations/xxxx_xx_xx_xxxxxx_create_contacts_table.php) and add the necessary fields as follows:

public function up()
{
    Schema::create('contacts', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->string('email');
        $table->text('message');
        $table->timestamps();
    });
}

public function down(): void
{
    Schema::dropIfExists('contacts');
}

Run the migration:

php artisan migrate

It will create the contacts table into the project database. Now, create a model for this migration:

php artisan make:model Contact

It will create contact model file app/models/Contact.php. Open this model file and update it as follows,

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Contact extends Model
{
    use HasFactory;

    protected $fillable = [
        'name',
        'email',
        'message',
    ];
}

Finally, start your Laravel development server:

php artisan serve

Now, visit http://127.0.0.1:8000/contact, and you should see your Livewire-powered Contact Form working dynamically!

Additional Features You Can Add

  • Real-time validation: Add wire:model.blur="name" to inputs.
  • Loading indicators: Use wire:loading to show a spinner while submitting.

Get Row Level Difference Between Two Tables in MySQL

Learn how to compare two MySQL tables row-by-row using JOINs and dynamic SQL to identify field-level differences efficiently.

To check row level differences between two records from two different tables in MySQL, where you want to see which fields have changed, follow these steps:

Using JOIN with CASE to Identify Row Level Differences in MySQL

You can compare each column individually to check row level difference and mark which ones have changed using this MySQL query.

SELECT
a.id,
CASE WHEN a.column1 = b.column1 THEN 'No Change' ELSE 'Changed' END AS column1_diff,
CASE WHEN a.column2 = b.column2 THEN 'No Change' ELSE 'Changed' END AS column2_diff,
CASE WHEN a.column3 = b.column3 THEN 'No Change' ELSE 'Changed' END AS column3_diff
FROM table1 a
JOIN table2 b ON a.id = b.id;

You can add as many columns as you want.

What this does:

  • Compares each field individually.
  • Marks "Changed" if different, otherwise "No Change".

Want to learn more about MySQL? Get MySQL book from https://amzn.to/45JXmH0

Dynamic Query for Large Tables

If you have many columns and don’t want to manually compare each, you can generate a query dynamically using MySQL Information Schema:

SELECT CONCAT(
'SELECT id, ',
GROUP_CONCAT(
'CASE WHEN t1.', COLUMN_NAME, ' <> t2.', COLUMN_NAME,
' THEN "', COLUMN_NAME, ' changed" ELSE "No Change" END AS ', COLUMN_NAME SEPARATOR ', '
),
' FROM table1 t1 JOIN table2 t2 ON t1.id = t2.id'
) AS query_text
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'table1' AND COLUMN_NAME != 'id';

This will generate a query that automatically checks differences for all columns. Execute the generated query and you will get the differences, where all cells are marked with "Changed" or "No Change".

Conclusion

These queries can help you identify difference between two tables cell by cell. It can be useful in many ways and reduce your so much time to identify a small difference in large data.

Do you stuck with any such problem? You can write me in the comments.

Disclaimer: This post contains affiliate links. If you use these links to buy something, I may earn a commission at no extra cost to you.