Playing with Barcodes in Python and Django
Why did the barcode break up with the QR code? Because it found her too square! Thank you ChatGPT for this awesome joke. 😉.
Barcodes are the unsung heroes of the business world, quietly working behind the scenes to keep things running smoothly. From inventory to shopping, they’re everywhere! Today we will create our very own Barcode Generator and Scanner web app using Django.
Setting Up
First things first, let’s set up our development environment. Ensure you have Django and the necessary dependencies installed by running the following commands:
pip install django pillow python-barcode pyzbar
pip freeze > requirements.txtCreating the Project Structure
Let’s kick off by creating our Django project along with two apps: barcode_generator for generating barcodes and barcode_scanner for scanning them. Keep things nice and modular.
django-admin startproject barcode_project
cd barcode_project
django-admin startapp barcode_generator
django-admin startapp barcode_scannerConfiguration
In the settings.py file, ensure you have the necessary configurations for media handling and in the urls.py file of the project we’ll configure URL routing.
# barcode_project/settings.py
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'# barcode_project/urls.py
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('generator/', include('barcode_generator.urls')),
path('scanner/', include('barcode_scanner.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)Now, create new urls.py files in each of our new app folders.
Defining the Models
We’ll define a Django model to store the code and the generated images.
# barcode_generator/models.py
from django.db import models
class GeneratedBarcode(models.Model):
code = models.CharField(max_length=100, unique=True)
image = models.ImageField(upload_to='media/barcodes/')
def __str__(self):
return self.codeRegister the model to see it in Admin portal
Go over to the admin.py of barcode_generator app and try to do it. It is not essential for our little project.
Run the Migrations
python manage.py makemigrations
python manage.py migrateGenerating Barcodes
Now, let’s create a view to generate barcodes dynamically using the python-barcode library. This view takes an alphanumeric code which will save a barcode image to the folder we specified in our models file.
# barcode_generator/views.py
import io
from django.http import HttpResponse
from barcode import Code39
from barcode.writer import ImageWriter
from .models import GeneratedBarcode
def generate_barcode(request, code):
code_obj = Code39(code, writer=ImageWriter())
buffer = io.BytesIO()
code_obj.write(buffer)
buffer.seek(0)
barcode_obj, created = GeneratedBarcode.objects.get_or_create(code=code)
if created:
barcode_obj.image.save(f'{code}.png', buffer, save=True)
action_performed = "created"
else:
action_performed = "fetched"
myResponse = f'Barcode "{code}" {action_performed} successfully! <a href="{barcode_obj.image.url}">IMAGE LINK</a>'
return HttpResponse(myResponse)First we create a Code39object. What is this Code39 thing, you ask. It is one of the most popular barcode types due to its versatility and simplicity. There are other formats like Code-128 and EAN-13 etc. Read more about Code39 if you are interested.
Lets get back to the code. The writer=ImageWriter() parameter indicates that the barcode should be rendered as an image.
Get Subham Sarangi’s stories in your inbox
Join Medium for free to get updates from this writer.
Then a BytesIO object is created, which is an in-memory binary stream that is used to store binary data. Simple enough.
After that, we write the barcode image data to the buffer using the write() method of the Code39 object and after that we move the file pointer to the beginning of the buffer using the seek method.
Define URLs for the views
# barcode_generator/urls.py
from django.urls import path
from . import views
app_name= "barcode_generator"
urlpatterns = [
path('generate/<str:code>/', views.generate_barcode, name='generate_barcode'),
]Run Server
Lets make some barcodes. Fire up the django development server.
python manage.py runserverNow you can access the barcode generator via http://127.0.0.1:8000/generator/generate/12345/
If everything goes well you’ll have generated an image which looks like this.
Scanning Barcodes
For barcode scanning functionality, we’ll utilize the pyzbar library to decode barcodes from uploaded images. As we have created a separate app barcode_scanner, head over to the views file in that folder.
# barcode_scanner/views.py
from django.shortcuts import render
from django.http import HttpResponse
from pyzbar.pyzbar import decode
from PIL import Image
from barcode_generator.models import GeneratedBarcode
def scan_barcode(request):
if request.method == 'POST':
try:
barcode_image = request.FILES['barcode_image']
image = Image.open(barcode_image)
decoded_objects = decode(image)
if decoded_objects:
barcode_data = decoded_objects[0].data.decode('utf-8')
barcode_data = barcode_data[:-1] # Removing the extra checksum
barcode_obj = GeneratedBarcode.objects.get(code=barcode_data)
return HttpResponse(f'Scanned Barcode: {barcode_obj.code}, Image: <a href="{barcode_obj.image.url}">IMAGE LINK</a>.')
else:
return HttpResponse('No barcode found.')
except Exception as e:
return HttpResponse(f'Error: {str(e)}', status=500)
else:
return render(request, 'barcode_scanner/scan.html')What are we doing here? When we’ll upload an image of a barcode the program will try to decode the code using the decode method of the pyzbar package. If we successfully decode it we’ll query the code in our database and show the results. That’s it.
Simple Html Template
<!-- barcode_scanner/templates/barcode_scanner/scan.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Scan Barcode</title>
</head>
<body>
<h1>Scan Barcode</h1>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<label for="barcode_image">Upload Barcode Image:</label><br>
<input required type="file" id="barcode_image" name="barcode_image" accept="image/*"><br><br>
<input type="submit" value="Scan Barcode">
</form>
</body>
</html>URL path
# barcode_scanner/urls.py
from django.urls import path
from . import views
app_name = 'barcode_scanner'
urlpatterns = [
path('scan/', views.scan_barcode, name='scan_barcode'),
]Upload the Image
If your server is still running, go to http://127.0.0.1:8000/scanner/scan/ and submit the form.
Enhancing Reliability (Extra)
To ensure data integrity, let’s implement a mechanism to move deleted barcode images to an archive directory. You can also delete the images if you want.
# barcode_generator/models.py
import os
from django.db.models.signals import pre_delete
from django.dispatch import receiver
from django.conf import settings
@receiver(pre_delete, sender=GeneratedBarcode)
def move_image_to_barchive(sender, instance, **kwargs):
if instance.image:
old_path = instance.image.path
media_root = settings.MEDIA_ROOT
barchive_dir = os.path.join(media_root, 'barchive')
if not os.path.exists(barchive_dir):
os.makedirs(barchive_dir)
filename = os.path.basename(old_path)
new_filename = f'deleted_{filename}'
new_path = os.path.join(barchive_dir, new_filename)
os.rename(old_path, new_path)Conclusion
And there you have it! With Django and a few Python libraries, we’ve built a Barcode Generator and Scanner web application. This example serves as a solid foundation that can be easily upgraded into a fully-fledged application tailored to meet the specific needs of your business or project, whether you’re managing inventory or processing transactions.
With further enhancements and integrations, such as user authentication, database optimization, and advanced barcode features, you can transform this prototype into a robust solution capable of handling real-world scenarios with ease.
Happy coding.










