django-appointment 📦¶
v3.13.0
Release Notes for Version 3.13.0¶
Introduction 📜¶
Version 3.13.0 builds on 3.12.0. It makes the package's pages and emails much easier to override: every staff
page gets the same context and named blocks, overrides can live in admin/ and booking/ folders, the calendar and
the forms take settings instead of script or widget changes, and every email gets the appointment's objects, full
links and a subject you can change from a template. A DEBUG-only page previews every email. The release also fixes a
booking form that failed without saying why, staff members refused on two of their own pages, and a management command
left out of the published package.
It is also a security release: it moves the package to Pillow 13.0.0, which fixes a long list of vulnerabilities in the earlier versions, and, because Pillow 13 no longer runs on Python 3.10, it drops Python 3.10.
There is no database change. See Breaking Changes and the migration guide before upgrading.
Security 🔒¶
- Pillow 13.0.0 is now required. Pillow 12.x and older have several known vulnerabilities, a few of them
critical: buffer overflows and out-of-bounds reads in the JPEG, TIFF and WMF/EMF decoders, decompression bomb
checks that can be bypassed, and denial of service through crafted PDF, BMP, GIF and other files. The package uses
Pillow to check the image uploaded for a service (
Service.image), so a crafted upload could reach those code paths.install_requiresnow asks forPillow>=13.0,<14.0, sopipupgrades it for you. See Pillow's 13.0.0 release notes for the full list.
New Features ✨¶
Easier staff page overrides 🧩¶
- The same context everywhere. Every staff page now gets
page_title,page_descriptionandback_url(where its Back link goes). The service pages also getmode(create,editorview), the day off, working hours and unavailability forms getform_action(the URL they post to), the staff list getsadmin_is_staff, and the profile page getsprofile_user, the staff member it shows (userstill holds it too, as before). - Named blocks. The Back link, the title and the buttons next to it are in
djappt_back,djappt_headinganddjappt_actions. An override can extend the default page and replace only those. - Folders. Overrides are looked for in
custom/admin/(staff pages) andcustom/booking/(client pages) first, then incustom/as before. An error page is looked for in the folder of the page that shows it. - Names. The thank-you, set-password and verification pages now also accept their default template's name
(
default_thank_you.html,set_password.html,enter_verification_code.html). The older names still work. - Messages in one place. Every page shows the Django messages through
appointment/_messages.html. Override it to restyle them everywhere, or with an empty file when your base template already shows them. - One confirm dialog. Every staff page has the confirm dialog and its script. A button opens it with
data-djappt-confirm="<url>"and thedata-confirm-title,data-confirm-messageanddata-confirm-actiontexts, and the dialog POSTs to that URL.
Schedule forms with plain field names 🗓️¶
The working hours and unavailability forms now post the model's field names with ISO values (date, start_time,
end_time, day_of_week), which is what the browser's date and time inputs send. A wrong value comes back as JSON
with the errors per field (status 400), and the default pages show each one under its field instead of in a modal.
The old date_raw, start_time_raw and end_time_raw fields are still read.
Calendar options 📅¶
APPOINTMENT_CALENDAR_OPTIONS sets the staff calendar's height ('fill', 'auto' or a number of pixels, with
fillRatio, bottomOffset and minHeight for 'fill') and passes any other key to FullCalendar (initialView,
firstDay...). A page with a footer no longer needs to redefine the height function. The appointment modal's Close
button and field wrappers are now found by data-djappt="close" and data-djappt="field".
Forms that follow your styles 📝¶
APPOINTMENT_FORM_CLASSESswaps the Bootstrap classes the package puts on its fields for yours, for example{'form-control': 'input', 'form-select': 'select'}.- The service duration is two inputs, hours and minutes, instead of a text field to fill as
HH:MM:SS. - The services a staff member offers are checkboxes in the forms, so
{{ form.services_offered }}draws them without extra work. - The staff forms have short help texts; the longer ones stay in the Django admin.
Emails 📧¶
- The same context everywhere. Every email now gets
company,site_url,current_yearanddashboard_url, and, when it is about an appointment,appointment,appointment_request,service,staff_member,client,client_name,appointment_urlandreschedule_url. A template can now place the date or the service where it wants, and link to the appointment. - Full links in every email. The links start with the address of the request that triggered the email. The staff notifications now get that request too, and a reminder keeps the address of the booking it was scheduled from.
- Subjects from templates. A
<name>.subject.txtfile next to an email template replaces its subject. - Default HTML emails for setting a staff password and for the verification code. They were plain text unless you wrote your own template.
- A "View Appointment" button in the new appointment and reminder emails sent to staff.
- Email preview. With
DEBUG = True, superusers can openapp-admin/email-preview/to see every email built for the latest appointment: the subject, the template used, and the HTML and text parts.
Translations 🌍¶
The new strings are in French and Spanish.
Good to Know 📝¶
{{ form.services_offered }}now draws checkboxes instead of a multiple select, and{{ form.duration }}draws two inputs. Templates that loop over the choices, or post a singledurationvalue, keep working.- The password and verification emails now use the package's HTML templates when you have no override. Before, they were sent as plain text.
- In the admin copy of the reminder,
first_nameis now empty: it was the client's name, in an email that isn't addressed to them. The client's first name is inclient_first_name.
Bug Fixes 🐛¶
- The booking details form failed without a message. A rejected field, such as a phone number in the wrong format, reloaded the page with nothing shown, so the Finish button seemed to do nothing. Each field now shows its error, with a summary at the top.
- Staff members were refused on their own pages.
add-staff-member/andupdate-user-info/without an id answered403to a staff member. They now mean the logged-in user, like the delete URLs since 3.12. - The
cleanup_appointment_requestscommand was missing. Its folders had no__init__.py, so the published package left it out although the docs describe it. - A day off with an empty date crashed. It gave a
500; the form errors are now returned. - Working hours on Sunday were rejected. Day
0was read as "no day". - The reminder's two copies could share one context. The admin copy changed the context after the client's email was queued; each copy now has its own.
Improvements 📈¶
- Dependency updates: Pillow, Django, phonenumbers, python-dotenv, setuptools and pymdown-extensions.
- The CI test matrix, the compatibility matrix and the demo
Dockerfileno longer use Python 3.10; the demo image now runs Python 3.12.
Breaking Changes 🚨¶
- Python 3.10 is no longer supported.
python_requiresis now>=3.11. Python 3.10 reached end of life in October 2026, and Pillow 13 does not support it. If you are still on 3.10, stay on 3.12.0 until you can upgrade the interpreter, and keep in mind that it cannot get the Pillow security fixes. - Pillow 13.0 is the minimum. If your project pins Pillow below 13.0,
pipwill refuse to install 3.13.0 together with it. Raise or remove that pin.
Nothing else breaks: the template, form and email changes keep the old names, fields and folders working. See "Good to Know" for what looks different.
Getting Started 🚀¶
Installation 📥:¶
Previous Version Highlights 🔙¶
Support & Feedback 📞¶
Feedback is welcome. For support, documentation, and further details, please refer to the documentation site or open an issue on GitHub.