Opened 2 months ago

Closed 2 months ago

Last modified 2 months ago

#35822 closed Bug (invalid)

App name hard-coded in collectstatic command forces name of overriding app name to be 'staticfiles'

Reported by: fishfin Owned by:
Component: contrib.staticfiles Version: 5.1
Severity: Normal Keywords: collectstatic
Cc: fishfin Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Sarah Boyce)

In django.contrib.staticfiles.management.commands.collectstatic, Command.set_options(), there is:

    ignore_patterns += apps.get_app_config("staticfiles").ignore_patterns

This looks for config class StaticFilesConfig in the app trying to overwrite ignore_patterns. Because Django forces the class name to match config name (in this case StaticFiles, the name of the app is forced to be staticfiles, it cannot be anything else. Either the hard-coding in collectstatic command set_options() should be changed, or document at https://docs.djangoproject.com/en/5.1/ref/contrib/staticfiles/#customizing-the-ignored-pattern-list should be changed for the example which shows the Config can be named MyStaticFilesConfig, which is clearly cannot be.

I have just started on Django (3-4 months) and I have looked at number of places, this info is missing, hence raising this ticket.

Change History (6)

comment:1 by Sarah Boyce, 2 months ago

Description: modified (diff)

comment:2 by Sarah Boyce, 2 months ago

Resolution: worksforme
Status: newclosed

I followed the documented example and it works as expected

These were my steps:

  • create a new Django project
  • set STATIC_ROOT = "static"
  • create a new app python manage.py startapp app1

Then followed the instructions

  • copy paste the overriden AppConfig with something in ignore_patterns
  • replace 'django.contrib.staticfiles' with that class path ('app1.apps.MyStaticFilesConfig') in INSTALLED_APPS setting

Command uses new custom setting

Also in the shell

>>> from django.apps import apps
>>> apps.get_app_config("staticfiles").ignore_patterns
['test']

comment:3 by fishfin, 2 months ago

These are my steps on Windows 11, Python 3.12.7, Django 5.1.2, I use pipenv: I know some of these steps don't matter, but I am unable to recreate what you said, so listing everything.

$ mkdir myvenv & cd myvenv & mkdir .venv & pipenv --python 3.12 & pipenv shell
$ pipenv install django
$ django-admin.exe startproject myproj & cd myproj
$ django-admin.exe startapp myapp

Edit myvenv/myproj/myproj/settings.py to:
1) Add STATIC_ROOT = "static" to the file
2) Replace item 'django.contrib.staticfiles' in INSTALLED_APPS with 'myapp.apps.MyappConfig' (pointing directly to the Config class instead of just app name).

Edit myvenv/myproj/myapp/apps.py to:
1) Replace

from django.apps import AppConfig
class MyappConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'myapp'

with

from django.contrib.staticfiles.apps import StaticFilesConfig
class MyappConfig(StaticFilesConfig):
    name = 'myapp'
    ignore_patterns = ["testpattern"]

Open shell:

$ cd myvenv/myproj
$ py manage.py shell
>>> from django.apps import apps
>>> apps.get_app_config('staticfiles').ignore_patterns
LookupError: No installed app with label 'staticfiles'.
>>> apps.get_app_config('myapp').ignore_patterns
['testpattern']

When you removed 'django.contrib.staticfiles' from settings.py, I am not sure how it is still able to find an app with that name. I am getting an error as I had expected as seen above. Changing MyappConfig.name to 'staticfiles' doesn't help either. Changing parent class of MyappConfig from StaticFilesConfig to AppConfig does not seem to be right.

Now, since we removed 'django.contrib.staticfiles', django doesn't know about its management/commands directory, so py manage.py collectstatic won't work.

$ py manage.py collectstatic
Unknown command: 'collectstatic'
Type 'manage.py help' for usage.

To make it work, I did the following:

$ mkdir myvenv/myproj/myapp/management/commands

Create following empty files:

myvenv/myproj/myapp/management/__init__.py
myvenv/myproj/myapp/management/commands/__init__.py
myvenv/myproj/myapp/management/commands/collectstatic.py
myvenv/myproj/myapp/management/commands/findstatic.py

Edit myvenv/myproj/myapp/management/commands/collectstatic.py and add following code:

from django.contrib.staticfiles.management.commands.collectstatic import Command

Edit myvenv/myproj/myapp/management/commands/findstatic.py and add following code:

from django.contrib.staticfiles.management.commands.findstatic import Command

Now:

$ py manage.py collectstatic
File "...\myvenv\.venv\Lib\site-packages\django\contrib\staticfiles\management\commands\collectstatic.py", line 103, in set_options
    ignore_patterns += apps.get_app_config("staticfiles").ignore_patterns
LookupError: No installed app with label 'staticfiles'.

...which is the same error I got in django shell. If I am doing something wrong, please let me know.

comment:4 by fishfin, 2 months ago

Resolution: worksforme
Status: closednew

Please see my previous comment, listed all steps to recreate.

Additionally:

>>> from django.apps import apps
>>> apps.app_configs
{'admin': <AdminConfig: admin>, 'auth': <AuthConfig: auth>, 'contenttypes': <ContentTypesConfig: contenttypes>, 'sessions': <SessionsConfig: sessions>, 'messages': <MessagesConfig: messages>, 'myapp': <MyappConfig: myapp>}

There's no staticfiles app.

Last edited 2 months ago by fishfin (previous) (diff)

comment:5 by Sarah Boyce, 2 months ago

Resolution: invalid
Status: newclosed

You added a name.
This

class MyappConfig(StaticFilesConfig):
    name = 'myapp'
    ignore_patterns = ["testpattern"]

should be:

class MyappConfig(StaticFilesConfig):
    ignore_patterns = ["testpattern"]

It inherits the name for StaticFilesConfig

So it works as documented

comment:6 by fishfin, 2 months ago

I removed the name.

from django.contrib.staticfiles.apps import StaticFilesConfig
class MyappConfig(StaticFilesConfig):
    # StaticFilesConfig.name = "django.contrib.staticfiles"
    ignore_patterns = ["testpattern"]

Works fine.

I missed a number of things here: INSTALLED_APPS can point to a specific AppConfig class, which in turn may have a name, which is the app Django loads. This also loads the management commands in django.contrib.staticfiles, so no overrides of commands were required. I removed myapp as there's no need create one just for staticfiles commands now, just shifted the overriding class to a file in myproj, and changed settings.INSTALLED_APPS likewise.

Thank you.

Note: See TracTickets for help on using tickets.
Back to Top