# Change reusable apps naming recommendation

**URL:** <https://forum.djangoproject.com/t/change-reusable-apps-naming-recommendation/25233>\
**Category:** Django Internals\
**Created:** [November 12, 2023, 2:47pm UTC](https://forum.djangoproject.com/t/change-reusable-apps-naming-recommendation/25233 "2023-11-12T14:47:39Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![adamchainz](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/adamchainz/32/26_2.png) [@adamchainz](https://forum.djangoproject.com/u/adamchainz)\
**Post date:** [November 12, 2023, 2:47pm UTC](https://forum.djangoproject.com/t/change-reusable-apps-naming-recommendation/25233/1 "2023-11-12T14:47:39Z")

</div>

The docs page [Advanced tutorial: How to write reusable apps](https://docs.djangoproject.com/en/stable/intro/reusable-apps/) covers packaging a Django app for PyPI. The “Choosing a name for your app” admonition recommends using an example module name `polls` with a package name `django-polls`.

I propose changing this page to recommend a module name of `django_polls` and making the admonition warn _against_ not using the `django_` prefix. The current approach causes name clashes which prevents using packages together. Here are the examples I know of:

- django-ratelimit had to rename after it collided with `ratelimit`: [Conflict with PyPI ratelimit · Issue #214 · jsocol/django-ratelimit · GitHub](https://github.com/jsocol/django-ratelimit/issues/214)
- @jeff recently reported a collision between `django-markdownify` and `markdownify` [Jeff Triplett: "🤷 It's rare that Python namespaces stop me from u…" - Mastodon](https://mastodon.social/@webology/111344527600725409)

I’m sure there are more.

---

<div class="post-metadata">

**Author:** ![drew](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/drew/32/559_2.png) [@drew](https://forum.djangoproject.com/u/drew)\
**Post date:** [November 12, 2023, 4:05pm UTC](https://forum.djangoproject.com/t/change-reusable-apps-naming-recommendation/25233/2 "2023-11-12T16:05:46Z")

</div>

Just to clarify, you’re still recommending keeping the PyPI package name as `django-polls`, right?

If so, hard +1 here. I find it annoying when the PyPI package name _doesn’t_ match the name of the Python module/package I’m importing.

---

<div class="post-metadata">

**Author:** ![andrewgodwin](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/andrewgodwin/32/2_2.png) [@andrewgodwin](https://forum.djangoproject.com/u/andrewgodwin)\
**Post date:** [November 12, 2023, 5:01pm UTC](https://forum.djangoproject.com/t/change-reusable-apps-naming-recommendation/25233/3 "2023-11-12T17:01:27Z")

</div>

I’m +1 on this - making people avoid a `django_` prefix on module names made more sense a decade or so ago when Python packages were rarer and Django was a bigger percentage of the ecosystem, but now it just seems like a silly recommendation.

---

<div class="post-metadata">

**Author:** ![adamchainz](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/adamchainz/32/26_2.png) [@adamchainz](https://forum.djangoproject.com/u/adamchainz)\
**Post date:** [November 12, 2023, 9:09pm UTC](https://forum.djangoproject.com/t/change-reusable-apps-naming-recommendation/25233/4 "2023-11-12T21:09:29Z")

</div>

Replies on [Mastodon](https://fosstodon.org/@adamchainz/111398129463350324) and [Twitter](https://twitter.com/AdamChainz/status/1723714638469099567) have been overwhelmingly positive.

---

<div class="post-metadata">

**Author:** ![adamchainz](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/adamchainz/32/26_2.png) [@adamchainz](https://forum.djangoproject.com/u/adamchainz)\
**Post date:** [November 12, 2023, 9:10pm UTC](https://forum.djangoproject.com/t/change-reusable-apps-naming-recommendation/25233/5 "2023-11-12T21:10:00Z")

</div>

> [@drew](#):
>
> Just to clarify, you’re still recommending keeping the PyPI package name as `django-polls`, right?

Yes, I’m proposing changing the module name to match it.

---

<div class="post-metadata">

**Author:** ![jrief](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/jrief/32/17040_2.png) [@jrief](https://forum.djangoproject.com/u/jrief)\
**Post date:** [November 13, 2023, 8:17am UTC](https://forum.djangoproject.com/t/change-reusable-apps-naming-recommendation/25233/6 "2023-11-13T08:17:19Z")

</div>

This means that the project structure would then look something like

```auto
django-polls
  + -- django_polls
      models.py
      setup.py
      urls.py
      ...
  setup.py
  MANIFEST.in
  README.md
  ...

```

In such a case every database table would be named `django_polls_modelname`. In my opinion this is too verbose and makes it harder to find the proper table. Moreover, static URL would start with `/static/django_pools/...` exposing the framework.

Would it be possible to create an empty folder inside the `django` packages, say `django/ext` where all Django third party apps would be installed? Then one would have to change their settings to

```auto
INSTALLED_APPS = [
    "django.contrib....",
    "django.ext.polls",
    ...
]

```

but otherwise all the naming conventions would remain the same.

---

<div class="post-metadata">

**Author:** ![adamchainz](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/adamchainz/32/26_2.png) [@adamchainz](https://forum.djangoproject.com/u/adamchainz)\
**Post date:** [November 13, 2023, 10:03am UTC](https://forum.djangoproject.com/t/change-reusable-apps-naming-recommendation/25233/7 "2023-11-13T10:03:47Z")

</div>

I think the database table name is better as it’s more explicit. Meta.db\_table can always be used in packages to disambiguate.

Static files are not restricted to the module name. They can use anything. But I’m also not concerned about framework name exposure since there are so many ways to fingerprint a site as using Django: find the admin, hit a 404 or CSRF error, check employees on GitHub, open positions on LinkedIn, …

Proposing an “ext” namespace is a bit beyond the current discussion. I’m not a fan of PEP 420 style namespace packages as I found they break many tools, hence: [flake8-no-pep420 · PyPI](https://pypi.org/project/flake8-no-pep420/)

---

<div class="post-metadata">

**Author:** ![shaib](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/shaib/32/35_2.png) [@shaib](https://forum.djangoproject.com/u/shaib)\
**Post date:** [November 13, 2023, 10:02pm UTC](https://forum.djangoproject.com/t/change-reusable-apps-naming-recommendation/25233/8 "2023-11-13T22:02:47Z")

</div>

I think @jrief has a point about the prefixes, and that point is even slightly wider than statics and database tables – e.g. it affects management commands that would need to refer to the app by its label.

Luckily, the app label [doesn’t really have to match the module name](https://docs.djangoproject.com/en/4.2/ref/applications/#django.apps.AppConfig.label); in fact, I’d even consider “having that cake while eating it” by changing the default label from _last component of `name`_ to _last component of `name`, with a prefix `django_` removed if found_ (of course, this requires taking care of backwards compatibility).

---

<div class="post-metadata">

**Author:** ![woutervh](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/woutervh/32/17019_2.png) [@woutervh](https://forum.djangoproject.com/u/woutervh)\
**Post date:** [November 14, 2023, 10:39pm UTC](https://forum.djangoproject.com/t/change-reusable-apps-naming-recommendation/25233/9 "2023-11-14T22:39:00Z")

</div>

When you register a new python-package on Pypi, it is registered by _name_ as defined in the package-metadata, and then this name is guaranteed to be unique across the entire repository.  
The name for the django-package is “Django”:

> pip install Django

but the names on Pypi are case-insensitive, so this also works:

> pip install django|DJANGO

Besides the case-insensitivity, Pypi also introduces an equivalence between hyphens and underscores  
because names with hypens are not valid python-modules.

so this is equivalent:

> pip install django-foo  
> pip install Django\_FOO

But the whole idea of this unique namespace on Pypi, is meant that the toplevel python-module provided by this package is unique, because that is what we use in code.

A proper name for a python-package is lowercased using dashes, eg “django-foo”  
with a corresponding module-name “django\_foo” belonging to this same unique namespace. In short:

> module\_name = package\_name.lower().replace(‘-’, ‘\_’)

This convention has probably been too implicit in the python-community.  
But a lot of code is using this convention when they have a soft-dependency on another package,  
they will try to import the module, and then assume the corresponding package has been installed.  
For example Flask tries to “import dotenv” and then assumes its soft-dependency “python-dotenv” is installed, but Flask will break when you have install “django-dotenv” installed.

Unfortunately the django-community has been promoting for a long time  
a different naming-pattern:

> module\_name = package\_name.lower().replace(‘-’, ‘_').replace('django_’, ‘’)

Now we have thousands of published python-packages, installing a python-module  
belonging to the unique namespace of ANOTHER PACKAGE.

You can install both packages without noticeable problems:

> pip install django-foo  
> pip install foo # completely independent project

> pip freeze  
> django-foo==…  
> foo==…

Pip will happily install both packages, and report both as being installed successfully.  
but the second one has DELETED & REPLACED the source-code of the first package.

AND NO TOOL WILL WARN YOU ABOUT THIS.

As a consequence, you can never use such packages in the same project.  
Or packages that depend on one of those.

This is not “shadowing”, it’s worse.  
This is not “dependency-hell”, it’s worse.  
Because you are silently deleting another package (but keeping its metadata intact).

Your quickfix-solution is to privately fork it, change the name of the module, and re-publish privately.

Publishing a python-package were the name of the module belongs to the namespace of different project is probably the most diabolical evil anti-pattern in the entire python-community.

Thanks to Adam for tackling this.

---

<div class="post-metadata">

**Author:** ![adamchainz](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/adamchainz/32/26_2.png) [@adamchainz](https://forum.djangoproject.com/u/adamchainz)\
**Post date:** [January 3, 2024, 9:38pm UTC](https://forum.djangoproject.com/t/change-reusable-apps-naming-recommendation/25233/11 "2024-01-03T21:38:47Z")

</div>

Following the positive feedback here, I have written a PR with the proposed changes: [Fixed #35084 -- Recommended 'django\_' prefix for reusable app modules. by adamchainz · Pull Request #17677 · django/django · GitHub](https://github.com/django/django/pull/17677).

---

<div class="post-metadata">

**Author:** ![interglobalmedia](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/interglobalmedia/32/23637_2.png) [@interglobalmedia](https://forum.djangoproject.com/u/interglobalmedia)\
**Post date:** [January 15, 2025, 2:59pm UTC](https://forum.djangoproject.com/t/change-reusable-apps-naming-recommendation/25233/12 "2025-01-15T14:59:38Z")

</div>

There is a problem with changing polls to Django-polls which n=then becomes “django\_polls” for the name of the package with the label of “polls”. In the tutorial, we were told to call the app polls. And the name of the project is django\_polls. This results in a directory name clash when I try and install the django\_polls app. Then I tried to fall back on polls. Which is fine, BUT I labelled it polls as well. And I can’t do that. So what label should I apply then? This problem actually is originally caused by the structure of the project. Basically, there is:

```auto
- django-polls/ # top level directory
- django_polls/ # name of the project
- templates/
- manage.py
- requirements.txt

```

So calling the polls app django\_polls for the sake of “convention” is problematic. Thanks!

---

<div class="post-metadata">

**Author:** ![interglobalmedia](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/interglobalmedia/32/23637_2.png) [@interglobalmedia](https://forum.djangoproject.com/u/interglobalmedia)\
**Post date:** [January 15, 2025, 3:09pm UTC](https://forum.djangoproject.com/t/change-reusable-apps-naming-recommendation/25233/13 "2025-01-15T15:09:19Z")

</div>

Was a problem waiting to happen. In the beginning, when I followed the app tutorial, I didn’t know that I was going to do advanced one until I found out about it. And then the name of the app is autogenerated based on what we give it. if we give it according to “convention” using django-\* for the name, and django\_\* for the name of the app used in the project itself, it WILL cause an issue. They should change the iinitiial naming of the app to fit the structure of the whole project taking into account the advanced tutorial! Thanks!

---

<div class="post-metadata">

**Author:** ![interglobalmedia](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/interglobalmedia/32/23637_2.png) [@interglobalmedia](https://forum.djangoproject.com/u/interglobalmedia)\
**Post date:** [January 15, 2025, 5:54pm UTC](https://forum.djangoproject.com/t/change-reusable-apps-naming-recommendation/25233/14 "2025-01-15T17:54:07Z")

</div>

I just wanted to clarify. I think they should not use dummy names for the project and the top level directory in the polls app tutorial. It should be more realistic. And if changes have to be made to make it work, then it should be done. Most people (including myself) don’t want to use dummy names like that. Sorry for any confusion!
