How to make log format fields optional?

I configured loggng like this in the realestate/settings.py file.

LOGGING = {
    "version": 1,
    "disable_existing_loggers": False,
    "formatters": {
        "standard": {
            "format": "%(asctime)s [%(levelname)s] %(message)s %(context)s"
        }
    },
    "handlers": {
        "file": {
            "level": "DEBUG",
            "class": "logging.FileHandler",
            "filename": "realestate.log",
            "formatter": "standard"
        },
        "console": {
            "class": "logging.StreamHandler",
            "formatter": "standard"
        }
    },
    "loggers": {
        "":
        {
            "handlers": ["file", "console"],
            "level": "DEBUG"
        }
    }
}

The logging format has additional format field, context.

"format": "%(asctime)s [%(levelname)s] %(message)s %(context)s"

I made a global logger in globals/logger.py that is used in views and services.

import logging

logger = logging.getLogger(__name__)

For example, register_post view function creates logs using this logger. The log messages are stored in globals/log_messages.py.
realestate\auth2\views.py:

from globals import log_messages
from globals.logger import logger

# ...

@ratelimit(key="ip", rate="10/m")
def register_post(request: HttpRequest, template: str):
    form = RegisterForm(request.POST)

    # 2 Input validation & sanitization
    if not form.is_valid():
        return render(request, template, {"form": form})

    cleaned_data = form.cleaned_data

    # 6 Error handling
    if auth_serv.email_taken(cleaned_data["email"]):
        messages.error(request, "Korisnik sa ovom imejl adresom već postoji.")

        # 5 Security logging
        logger.warning(log_messages.auth_view["register_email_taken"])
        return redirect(reverse("register"))

    if auth_serv.phone_taken(cleaned_data["phone"]):
        messages.error(request, "Korisnik sa ovim brojem telefona već postoji.")

        # 5 Security logging
        logger.warning(log_messages.auth_view["register_phone_taken"])
        return redirect(reverse("register"))

    user = auth_serv.create(cleaned_data)
    login2(request, user)

    # 5 Security logging
    logger.info(log_messages.auth_view["register_success"], extra={"context": {"user_id": user.pk}})
    return redirect(reverse("listing-list"))

Some logs pass extra parameters:

logger.info(log_messages.auth_view["register_success"], extra={"context": {"user_id": user.pk}})

And some logs don’t.

logger.warning(log_messages.auth_view["register_email_taken"])
logger.warning(log_messages.auth_view["register_phone_taken"])

I keep getting key error for context. Perhaps it has to with context not being passed into some logs.

--- Logging error ---
Traceback (most recent call last):
  File "C:\_dev\Python314\Lib\logging\__init__.py", line 472, in format
    return self._format(record)
           ~~~~~~~~~~~~^^^^^^^^
  File "C:\_dev\Python314\Lib\logging\__init__.py", line 468, in _format
    return self._fmt % values
           ~~~~~~~~~~^~~~~~~~
KeyError: 'context'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\_dev\Python314\Lib\logging\__init__.py", line 1151, in emit
    msg = self.format(record)
  File "C:\_dev\Python314\Lib\logging\__init__.py", line 999, in format
    return fmt.format(record)
           ~~~~~~~~~~^^^^^^^^
  File "C:\_dev\Python314\Lib\logging\__init__.py", line 715, in format
    s = self.formatMessage(record)
  File "C:\_dev\Python314\Lib\logging\__init__.py", line 684, in formatMessage
    return self._style.format(record)
           ~~~~~~~~~~~~~~~~~~^^^^^^^^
  File "C:\_dev\Python314\Lib\logging\__init__.py", line 474, in format
    raise ValueError('Formatting field not found in record: %s' % e)
ValueError: Formatting field not found in record: 'context'
Call stack:
  File "D:\Documents\_Dokumenti\Projekti\_Master\Real Estate App\Django\secure\realestate\manage.py", line 22, in <module>
    main()
  File "D:\Documents\_Dokumenti\Projekti\_Master\Real Estate App\Django\secure\realestate\manage.py", line 18, in main
    execute_from_command_line(sys.argv)
  File "D:\Documents\_Dokumenti\Projekti\_Master\Real Estate App\Django\secure\venv\Lib\site-packages\django\core\management\__init__.py", line 443, in execute_from_command_line
    utility.execute()
  File "D:\Documents\_Dokumenti\Projekti\_Master\Real Estate App\Django\secure\venv\Lib\site-packages\django\core\management\__init__.py", line 437, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "D:\Documents\_Dokumenti\Projekti\_Master\Real Estate App\Django\secure\venv\Lib\site-packages\django\core\management\base.py", line 420, in run_from_argv
    self.execute(*args, **cmd_options)
  File "D:\Documents\_Dokumenti\Projekti\_Master\Real Estate App\Django\secure\venv\Lib\site-packages\django\core\management\commands\runserver.py", line 69, in execute
    super().execute(*args, **options)
  File "D:\Documents\_Dokumenti\Projekti\_Master\Real Estate App\Django\secure\venv\Lib\site-packages\django\core\management\base.py", line 464, in execute
    output = self.handle(*args, **options)
  File "D:\Documents\_Dokumenti\Projekti\_Master\Real Estate App\Django\secure\venv\Lib\site-packages\django\core\management\commands\runserver.py", line 110, in handle
    self.run(**options)
  File "D:\Documents\_Dokumenti\Projekti\_Master\Real Estate App\Django\secure\venv\Lib\site-packages\django\core\management\commands\runserver.py", line 117, in run
    autoreload.run_with_reloader(self.inner_run, **options)
  File "D:\Documents\_Dokumenti\Projekti\_Master\Real Estate App\Django\secure\venv\Lib\site-packages\django\utils\autoreload.py", line 681, in run_with_reloader
    logger.info(

How do I make log format fields optional and not get such errors?

From the docs at: logging — Logging facility for Python — Python 3.14.7 documentation

If you choose to use these attributes in logged messages, you need to exercise some care. In the above example, for instance, the Formatter has been set up with a format string which expects ‘clientip’ and ‘user’ in the attribute dictionary of the LogRecord. If these are missing, the message will not be logged because a string formatting exception will occur. So in this case, you always need to pass the extra dictionary with these keys.

[Emphasis added]

You have a number of different options here to handle this:

  • Create a custom Formatter that would define a default for context
    • Or possibly select from one of two defined formats depending upon the existance of the extra context
  • Add the extra context to all your logging calls
  • Define two logger instances in your module, one using a formatter with the context and one without.
  • Define a wrapper function for the loggers to add a context if it doesn’t exist

See Logging Cookbook — Python 3.14.7 documentation for some examples

I tried adding extra to the logs logger.warning(log_messages.auth_view["register_email_taken"], extra={"context": None}), but that didn’t work. I still got key errors.

The error is being thrown by Django itself, not your code. You either need to isolate the Django logger messages from your application’s messages by defining multiple loggers, or write your own formatter class.