Use Pathlib in Your Django Settings File2020-03-16
Django’s default settings file has always included a
I call it a “pseudo-setting” since it’s not read by Django itself.
But it’s useful for configuring path-based settings, it is mentioned in the documentation, and some third party packages use it.
(One that I maintain, the Scout APM Python integration, uses it.)
Django has, up until now, defined it as:
This changes in version 3.1, which as I write is still months in the future. Thanks to a contribution by Jon Dufresne and Curtis Maloney, it’s instead defined using pathlib:
Note this is in the new project template only. If you upgrade an older project to Django 3.1, your settings file won’t be changed.
pathlib was added to Python’s standard library in Python 3.4, thanks to PEP 428.
All file-path using functions across Python were then enhanced to support
pathlib.Path objects (or anything with a
__fspath__ method) in Python 3.6, thanks to PEP 519.
pathlib is great!
It has an easier API than
os.path.join(), allows method chaining, and handles path normalization automatically.
See how you can define a subdirectory using
BASE_DIR / 'subdir'.
If you want to read more, see Trey Hunner’s articles Why you should be using pathlib and No really, pathlib is great.
Even though this is in the future (or maybe not, if you are in the future), you can convert your projects to use it today. (Or, if you are using Django 3.1+, but your project was started before, you can convert.)
If you haven’t used pathlib before, I think this is a great place to try it out.
To migrate, you’d pretty much want to copy the commit from Django itself.
First copy the new definition of
BASE_DIR, as above.
Then, update your other settings that use it.
For example, the documentation changed around defining
In theory, on Python 3.6+,
Path() objects should be accepted anywhere that strings are.
This should mean you don’t need to worry about converting all uses at the same time, as the old
os.path.join() pattern accepts
Path() objects as well.
However in practice some code paths still expect strings as they use non-path operations.
For example some settings in Django that expected strings were found and had
Path() support added in commit 77aa74cb (again, for Django 3.1).
For older versions or third party package settings, you will probably need to use
str() around the result.
For example, if you are using the SQLite database backend, before opening the database file it checks if the path contains
For this to work, you’ll need to use
str() when passing it the path in
For any other errors you might encounter, using
str() should fix them.
Thanks to Carlton Gibson, Curtis Maloney, Jon Dufresne, and Nick Pope for changing this in Django 3.1. Hope this helps your use of paths,
Want better tests? Check out my book Speed Up Your Django Tests which teaches you to write faster, more accurate tests.
One summary email a week, no spam, I pinky promise.
- Moving to Django 3.0's Field.choices Enumeration Types
- Common Issues Using Celery (And Other Task Queues)
Tags: django, python
© 2021 All rights reserved.