Django Versatility does not stop at creating APIs or Impressive Web apps, We can also create packages from the apps within our Django Projects. In this article, we’ll be creating a package, uploading it to test.pypi and looking at how to use that package with other projects.
How Reusable?
Before We begin, it is crucial to understand how the package we intend to create will work in the projects of others. Will our package gives functions to the project, or will it work as a standalone and interact with the database? Is my package going to need data from the project? Will my package pass data to the template? Etc. Answering these questions can help you better grasp how to structure your package.
Creating your Package
We’ll be using This repo (also below) to create our package. It’s a simple memo app that allows users to save and check memos if it’s a task.
GitHub - gr1nch3/django_memo: A simple Django memo application
The project structure should be like this:
django_memo
|_django_memo
|_memo
|_theme
|_manage.py
The first step is to move the app we want to turn into a package to another folder, you can copy or cut it to the folder. You should pick a meaningful name for the folder, since it’s what your package will be referenced by. I’ll name mine django-memo. Outside that folder, we will create a virtual environment.(make sure your package and its virtual environment are in a separate workspace or folder
# first
python3 -m venv my-env
# second
source my-env/bin/activate # macos/linux
my-env/scripts/activate.bat # windows
Next is to install twine and setuptools, we’ll use them to build our package and test it.
pip install twine setuptools
Extras
In the folder you moved your app to(django-memo in my case), we are going to add the following files that will configure and build your package: *setup.cfg, LICENSE, pyproject.toml, README.md **and **MANIFEST.in *.
pyproject.toml
Add the following to your **pyproject.toml **file, and make sure the setuptools version matches the one you’ve installed.
[build-system]
requires = ['setuptools >= 65.3.0', 'wheel']
build-backend = 'setuptools.build_meta:__legacy__'
setup.cfg
This file contains the metadata for **PyPI **and other requirements for your package. Make sure to check the requirements for your package version and set accordingly.
[metadata]
name = django-memo
version = 1.2
description = A Django app to take and manage memo
readme = "README.md"
long_description = file: README.md
long_description_content_type=text/markdown
url = [https://www.example.com/](https://www.example.com/)
author = gr1nch3
author_email = example[@gmail.com](mailto:lloydm763@gmail.com)
license = MIT License
classifiers =
Environment :: Web Environment
Framework :: Django
Framework :: Django :: 4.0 # set your version
Intended Audience :: Developers
License :: OSI Approved :: MIT License
Operating System :: OS Independent
Programming Language :: Python
Programming Language :: Python :: 3
Programming Language :: Python :: 3 :: Only
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Topic :: Communications :: Chat
[options]
include_package_data = true
packages = find:
python_requires = >=3.9
install_requires =
Django >= 4.0 # set your version
Note: **the **long_description **by default is .rst, but .md works for me. The **long_description **and **long_description_content_type **needed to be configured like that to pass the **twine check.
README
Your README file needs to be properly written in order to upload to pypi. It should also tell how to set up your package in a Django project.
=====
Memo
=====
memo is a Django app to create memos and manage them
Detailed documentation is in the "docs" directory.
Quick start
-----------
1. Add "memo" to your INSTALLED_APPS setting like this::
INSTALLED_APPS = [
...
'memo',
]
2. Include the memo URLconf in your project urls.py like this::
path('memo/', include('memo.urls')),
3. Run ``python manage.py migrate`` to create the memo models.
4. Visit '[http://127.0.0.1:8000/memo/'](http://127.0.0.1:8000/memo/') to check out your memos
LICENSE
The License will contain the license for your package. We’ll use a MIT License
# MIT License
Copyright (c) [year] [your full name]
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
MANIFEST.in
The manifest will include other files, folders and templates that your package needs.
include LICENSE
include README.md
recursive-include docs *
setup.py
required to build the package
from setuptools import setup
setup()
After all the configurations, your package should look like this:
...(workspace or folder)
|_my-env
|_django-memo
|_memo
|_LICENSE
|_MANIFEST.in
|_pyproject.toml
|_README.md
|_setup.cfg
|_setup.py
Configuring our model
In this section, we will configure our memo model to work with the projects it will be installed in. Since the memo model requires an abstract user. We’ll set it so that the package gets the user model from the settings. Just passing the user model to the settings (with AUTH_USER_MODEL) and accessing it as settings.AUTH_USER_MODEL for our memo model would pass the model as a string. So we’ll use the get_user_model() from django.contrib.auth. Our memo model structure will change to the following:
from django.db import models
from django.contrib.auth import get_user_model # new
MemoUser = get_user_model() # new
# Create your models here.
# ---------------------------------------------------------------------------- #
# model of the memo detail #
# ---------------------------------------------------------------------------- #
class Memo(models.Model):
# new
user = models.ForeignKey(MemoUser, on_delete=models.CASCADE)
title = models.CharField(max_length=100)
memo = models.TextField(blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
is_completed = models.BooleanField(default=False)
def __str__(self):
return self.title
class Meta:
db_table = 'memo'
verbose_name = 'Memo'
verbose_name_plural = 'Memos'
ordering = ['-created_at']
Note: If you were to pass a model to the package and use it as a foreign key, you can check out the code for the get_user_model() function, it works for passing other models as well, and you would only need to set it up in the settings.py.
Testing our Package
At this point, we’ve built and structured our app and have all files needed to turn it to a package.
Build
There are two ways we could create the dist folder that contains the package.
We could use setuptools and run the command python setup.py sdist in the directory that contains our app and the packaging files, and we would get a build that would still pass the twine check .
We could also use the python build module’s python3 -m build command and get a similar result, and we would also get the wheel for the package
Test
After you have created your dist folder, run the command twine check dist/* in the folder that contains the dist and you should see a message like this:
# if you used the first method
Checking dist/django-memo-1.2.tar.gz: PASSED
# if you used the second method
Checking dist/django_memo-1.2-py3-none-any.whl: PASSED
Checking dist/django-memo-1.2.tar.gz: PASSED
Installing our Package
To install our package locally in a project, we can run the following command: python -m pip install -U ./dist/django-memo-1.2.tar.gz .
Uploading our Package
We are going to upload our package to test.PyPI. Make sure to create an account. When done, go to account settings and add API token and create a token. Remember to copy your token someplace safe because you’ll be using it for uploads to test.PyPI. To upload to the real PyPI, you can use your credentials.
After creating the token, in your terminal, run the following command:
python3 -m twine upload --repository testpypi dist/*
You’ll be prompted for a username, and you should set the username value to token . When you receive the prompt for a password, you add the token value you copied for the password. Results should be something similar:
Uploading django_memo-1.2-py3-none-any.whl
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 10.7/10.7 kB • 00:05 • 14.2 MB/s
Uploading django-memo-1.2.tar.gz
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 9.6/9.6 kB • 00:00 • 9.6 MB/s
View at:
[https://test.pypi.org/project/django-memo/1.2/](https://test.pypi.org/project/django-memo/1.2/)
Congratulations! You Just created your first working package! If you follow the link from the result in your terminal, you should see your package on test.PyPI.
To view the package, check it out in this repo:
GitHub - gr1nch3/django-memo
Top comments (0)