DEV Community

gr1nch3
gr1nch3

Posted on

Creating a Reusable Django app

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Next is to install twine and setuptools, we’ll use them to build our package and test it.

pip install twine setuptools
Enter fullscreen mode Exit fullscreen mode

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__'
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

MANIFEST.in

The manifest will include other files, folders and templates that your package needs.

include LICENSE
include README.md
recursive-include docs *
Enter fullscreen mode Exit fullscreen mode

setup.py

required to build the package

from setuptools import setup

setup()
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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']
Enter fullscreen mode Exit fullscreen mode

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.

  1. 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 .

  2. 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
Enter fullscreen mode Exit fullscreen mode

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/*
Enter fullscreen mode Exit fullscreen mode

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/)
Enter fullscreen mode Exit fullscreen mode

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)