Save your Django uploaded files using NanoIDs for file names or store them in directories named with NanoIDs.
Project description
Django-NanoID-Integration
Django-NanoID-Integration is a Django library that seamlessly integrates NanoID - a compact, secure, and URL-friendly unique string ID into your projects.
Key Features
-
A custom
NanoIDField
for your Django models -
An
upload_to_nanoid
method forImageField
andFileField
, ensuring unique filenames -
Predefined character sets for generating safe NanoID strings
This library draws inspiration from:
Why Use NanoID?
The Problem with Sequential IDs
Using sequential integers as primary keys in URLs can expose sensitive information, which you likely want to keep confidential. I allows malicious users to easily access your data by modifying the URL. Sequential IDs can reveal information about the size of your database and growth rate, potentially compromising business intelligence.
The Problem with UUIDs
While using UUID
s offers mathematically guaranteed uniqueness and is supported by Django without additional libraries, it has the drawbacks of creating unwieldy and unattractive URLs, consuming more storage space (typically 128 bits) and can be slower to index and query in databases.
The Solution: NanoID
NanoID is a solution that offers a balance between uniqueness and URL-friendliness. It generates compact, secure, and unique identifiers, making it an excellent choice for primary keys in URLs. NanoID helps:
-
Maintain data privacy by avoiding sequential integers in URLs
-
Ensure unique, manageable URLs and stable URL structures, even if product names change
-
Generate shorter IDs compared to UUIDs (typically 21 characters)
-
Offer better performance in databases due to smaller size
-
Allow customization of ID length and character set
-
Offer language-agnostic implementation with ports available for many programming languages
-
Improve user experience with more readable and memorable IDs
Installation
To install Django-NanoID-Integration, use pip:
pip install django-nanoid-integration
Add django_nanoid_integration
to your INSTALLED_APPS
in settings.py
:
INSTALLED_APPS = [
...
'django_nanoid_integration',
...
]
Using NanoIDField
The NanoIDField
is a custom Django model field that integrates NanoID functionality directly into your models.
Adding a NanoIDField
to Your Model
Here's an example of how to add a NanoIDField
to your Django model:
from django.db import models
from django_nanoid_integration import NanoIDField
class User(models.Model):
id = NanoIDField(primary_key=True)
name = models.CharField(max_length=100)
Customizing the NanoID
You can specify a custom alphabet and size for the NanoID. The following example creates a NanoID like B902_fA1:
from django.db import models
from django_nanoid_integration import NanoIDField
class User(models.Model):
id = NanoIDField(primary_key=True, alphabet='_-0123456789ABCdef', size=8)
name = models.CharField(max_length=100)
Using Predefined Alphabets
You can also use predefined alphabets for generating NanoIDs. The available choices are:
-
safe: Contains characters that are easily distinguishable and avoid confusion, such as excluding similar-looking characters like '1' and 'I' or '0' and 'O'. This set combines safe uppercase and lowercase letters along with safe numbers. It is also the default choice when using
NanoIDField()
-
unsafe: A broader set that includes both safe and potentially confusing characters, such as similar-looking letters and numbers
-
numbers: Only numeric characters (0-9)
-
safe_letters: A combination of safe uppercase and lowercase letters
-
safe_letters_uppercase: Only safe uppercase letters
-
safe_letters_lowercase: Only safe lowercase letters
-
safe_letters_uppercase_and_numbers: Safe uppercase letters combined with safe numbers
-
safe_letters_lowercase_and_numbers: Safe lowercase letters combined with safe numbers
Here’s an example using the predefined numbers
alphabet, which will create a NanoID like 40349
:
from django.db import models
from django_nanoid_integration import NanoIDField
class User(models.Model):
id = NanoIDField(primary_key=True, alphabet_predefined='numbers', size=5)
name = models.CharField(max_length=100)
Ensuring Unique NanoIDs
When generating NanoIDs, there is a small chance that two identical IDs might be created, especially if they are very short. This is known as a "collision." You can use the Nano ID Collision Calculator to check the likelihood of collisions for different ID lengths and character sets.
To ensure uniqueness, use the UniqueNanoIDMixin
and set unique=True
for the field. Primary Keys are set unique=True
by default. You can also specify the number of attempts to generate a unique ID with nanoid_max_attempts
(default is 10).
Here's an example of how to use the UniqueNanoIDMixin
in your Django models:
from django.db import models
from django_nanoid_integration import NanoIDField, UniqueNanoIDMixin
class User(UniqueNanoIDMixin, models.Model):
id = NanoIDField(primary_key=True)
another_unique_nanoid = NanoIDField(alphabet_predefined='numbers', size=5, unique=True)
name = models.CharField(max_length=100)
nanoid_max_attempts = 10
Regenerating NanoIDs
You can regenerate a NanoID for a specified field, useful for updating non-primary key fields. Use force=True
to bypass safety confirmations, but be cautious with foreign key relations. They are not supported yet.
Here's an example of how to use regenerate_nanoid
:
user = User.objects.get(email='email@example.com')
user.regenerate_nanoid('unique_nanoid_field', force=True)
Using upload_to_nanoid
Function
The upload_to_nanoid
function in ImageField
or FileField
generates unique filenames, enhancing security and uniqueness.
Settings adjustment
Add MEDIA_URL
and MEDIA_ROOT
to your settings.py
if not yet done. This step is crucial for handling media files in Django.
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'
Also:
-
Ensure
BASE_DIR
is correctly defined -
Ensure
urlpatterns
inurls.py
are set to serve Media Files during Development -
Ensure your custom storage backend is configured properly (if you use it)
Adding upload_to_nanoid
to Your Model
from django.db import models
from django_nanoid_integration import upload_to_nanoid
class UserProfile(models.Model):
picture = models.ImageField(upload_to=upload_to_nanoid('pictures'))
anyfile = models.FileField(upload_to=upload_to_nanoid('files'))
Key Parameters for upload_to_nanoid
preserve_original_filename
The preserve_original_filename
parameter controls whether to keep the original filenames when uploading files. By default, it is set to False
.
-
If
False
, files are uploaded with a unique identifier like/media/pictures/{nanoid}.jpg
-
If
True
, files retain their original filenames within a directory formatted as/media/pictures/{nanoid}/original.jpg
from django.db import models
from django_nanoid_integration import upload_to_nanoid
class UserProfile(models.Model):
...
picture = models.ImageField(upload_to=upload_to_nanoid('pictures', preserve_original_filename=True))
...
remove_query_strings
The remove_query_strings
parameter determines whether to remove query strings from the filenames of uploaded files, ensuring a clean and consistent file name. By default, it is set to True
.
from django.db import models
from django_nanoid_integration import upload_to_nanoid
class UserProfile(models.Model):
...
picture = models.ImageField(upload_to=upload_to_nanoid('pictures', remove_query_strings=True))
...
alphabet
, size
The alphabet
and size
parameters allow you to specify a custom alphabet and length for the NanoID, exactly as in the NanoIDField
. This example creates a filepath like /media/pictures/B902_fA1.jpg
:
from django.db import models
from django_nanoid_integration import upload_to_nanoid
class UserProfile(models.Model):
...
picture = models.ImageField(upload_to=upload_to_nanoid('pictures', alphabet='_-0123456789ABCdef', size=8))
...
alphabet_predefined
You can also use predefined alphabets for generating NanoIDs, similar to the NanoIDField
. The available choices are also the same as in NanoIDField
.
from django.db import models
from django_nanoid_integration import upload_to_nanoid
class UserProfile(models.Model):
...
picture = models.ImageField(upload_to=upload_to_nanoid('pictures', alphabet_predefined='numbers', size=1))
...
Global Configuration in settings.py
You can set global options for the NanoID generator in your settings.py
. If both NANOID_ALPHABET
and NANOID_ALPHABET_PREDEFINED
are set, NANOID_ALPHABET
takes precedence.
NANOID_ALPHABET = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-'
NANOID_ALPHABET_PREDEFINED = 'safe'
NANOID_SIZE = 10
Database Migration Instructions
After making changes to your models, update your database schema. Additionally, if you change NANOID_ALPHABET
, NANOID_ALPHABET_PREDEFINED
, or NANOID_SIZE
in settings.py
, run these commands:
python manage.py makemigrations
python manage.py migrate
Contributing
Your contributions are welcome and appreciated! This project is actively maintained, and I am eager to hear your feature requests and suggestions. Follow these steps to get started:
-
Fork the repository: Click the "Fork" button on the repository's GitHub page to create a copy of the repository under your own GitHub account
-
Clone your fork: Clone your forked repository to your local machine (git clone https://github.com/spechtx/django-nanoid-integration)
-
Create a new branch: Create a new branch for your feature or bug fix (git checkout -b feature-branch)
-
Make your changes: Implement your changes or new features
-
Commit your changes: Commit your changes with a descriptive commit message (git commit -m 'Add new feature')
-
Push your branch: Push your branch to your forked repository on GitHub (git push origin feature-branch)
-
Open a Pull Request: Navigate to the original repository on GitHub and click the "New Pull Request" button. Compare your feature branch with the original repository's branch (main) and submit the pull request.
I look forward to your contributions!
License
This project is licensed under the MIT License. See the LICENSE file for details.
Roadmap
-
Update Foreign Key Relations: Ensure that foreign key relations are correctly updated when regenerating NanoIDs
-
Write Tests: Develop comprehensive tests to ensure the reliability and stability of the NanoID integration.
Acknowledgements
This library draws inspiration from:
Enjoy using Django-NanoID-Integration? Give us a ⭐ on GitHub and share your experience!
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file django-nanoid-integration-0.1.0.tar.gz
.
File metadata
- Download URL: django-nanoid-integration-0.1.0.tar.gz
- Upload date:
- Size: 16.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.0 CPython/3.12.3
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 0b97d194f67949ea7a1103f06ac05eda50d272e13213882d1e8d1bbbb15dd11e |
|
MD5 | 0e8c079dcff7228a0484d459193b3098 |
|
BLAKE2b-256 | 30a0fd18d59784cb15c05f67ec81879e37f20aa8812021f012a4df2897bbba00 |
File details
Details for the file django_nanoid_integration-0.1.0-py3-none-any.whl
.
File metadata
- Download URL: django_nanoid_integration-0.1.0-py3-none-any.whl
- Upload date:
- Size: 14.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.0 CPython/3.12.3
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 69dc47a40d284f382d67ec72a902dca5dc8102334f7427bcf3f62e728cc8595d |
|
MD5 | edecaf0de21a0aab9df9cde2890a9028 |
|
BLAKE2b-256 | 69e40f2996c6c60471fee63b7bc8d51a71587331e0d7a36f12406b527222e0d2 |