Django CORS headers – You want to use ‘Cache-Control’

I was happily writing React app, and at one point, I realized I have to not have any cache at all to access Django API. So, I added,

headers: { "cache-control": "no-store" }

Then, Django API complains. I knew I already set up CORS middleware so I thought I am all set. For development, Django/React are being developed and need to do a bit of HTTP dance so I disabled the CORS check, I thought.
Long sotry short, as I read the code, what React app is complaining is that the “cache-control” is not part of approved headers.
Take a look at "site-packages/corsheaders/conf.py"

class Settings:
    """
    Shadow Django's settings with a little logic
    """

    @property
    def CORS_ALLOW_HEADERS(self):
        return getattr(settings, "CORS_ALLOW_HEADERS", default_headers)

    @property
    def CORS_ALLOW_METHODS(self):
        return getattr(settings, "CORS_ALLOW_METHODS", default_methods)

    @property
    def CORS_ALLOW_CREDENTIALS(self):
        return getattr(settings, "CORS_ALLOW_CREDENTIALS", False)

    @property
    def CORS_PREFLIGHT_MAX_AGE(self):
        return getattr(settings, "CORS_PREFLIGHT_MAX_AGE", 86400)

    @property
    def CORS_ORIGIN_ALLOW_ALL(self):
        return getattr(settings, "CORS_ORIGIN_ALLOW_ALL", False)
...

In my setting, I did "CORS_ORIGIN_ALLOW_ALL=true"so that part Okayes any origin, but to use cache-control header, you now have to set "CORS_ALLOW_HEADERS".
Since setting CORS_ALLOW_HEADERS in settings.py completely replaces the value, I copied the default header, and set it as follows:

CORS_ALLOW_HEADERS = [
    "accept",
    "accept-encoding",
    "authorization",
    "content-type",
    "dnt",
    "origin",
    "user-agent",
    "x-csrftoken",
    "x-requested-with",
    "cache-control",
    "credentials",
    "http-access-control-request-method",
]

# if you want to allow all. You could use whitelist instead.
CORS_ORIGIN_ALLOW_ALL = True

Now, my React app is back to accessing Django.

Django testing with django-pytest

Pfff. Just finished writing mere 3 tests, and took me a long time. As usual, it’s probably a good idea to read the docs carefully. I didn’t and it bit my shiny hiny badly.

This is about “Testing Transaction” of Django pytest. Quote “Django itself has the TransactionTestCase which allows you to test transactions and will flush the database between tests to isolate them.”

I wrote a small test fixture that creates a few records. However, as each test runs within single transaction, subsequent query against database does not return the records created by the fixture function. For example, as you create a user, and the post-save creates one-to-one user profile, quering the user against database in normal operation does work but not for the test, as the User records have not been commited to the database yet. This puzzled me like a day. First, I checked that the database connection is right, the database is working, etc. After checking this, it became clear that the test is running in a transaction, and I had to commit for the fixtures to be on the database so my tests can query.

As a Django and pytest noob, this took me a day to get to a meaningful google question, and I hit this blog titled “Transaction tests in Pytest”. I finally saw a magic keyword “transaction=True” in the db test marker, and went back to the doc.

“Testing Transactions” is right under “Enabling Database Access in Tests so I should not have missed, but I glanced over and didn’t realize what it meant.

My excuse was that, when I was writing the test, I did something funky and the fixture setup was running before the test transaction in place. After I refactored the test files around, the feature kicked in, and made me really confused. So, this was my stupidity, and this is what I learned today.