Django Migrations don't work, Says improperly configured

Hello all, I have been perplexed for a few hours due to an error that arises when I migrate, when I run makemigrations it says there have been no changes detected, even when i delete the database itself, and when i run migrate it says the engine is improperly configured even though we are just using the default sqlite at the moment, and haven’t changed that part of the settings.py file. The only issue that i can really see that would occur would be due to my linking of cloudinary, though all AI models I’ve taken this to seem to disagree.

Cloudinary Integration, which uses a .env file

from cloudinary_storage.storage import MediaCloudinaryStorage
from pathlib import Path
from dotenv import load_dotenv
import cloudinary
import cloudinary.uploader
import cloudinary.api
import os

load_dotenv()


cloudinary.config(
    cloud_name=os.getenv('CLOUDINARY_CLOUD_NAME'),
    api_key=os.getenv('CLOUDINARY_API_KEY'),
    api_secret=os.getenv('CLOUDINARY_API_SECRET')
)

DEFAULT_FILE_STORAGE = 'cloudinary_storage.storage.MediaCloudinaryStorage'
MEDIA_URL = '/media/'

Database Configuration

BASE_DIR = Path(__file__).resolve().parent.parent
DATABASES = {
    'default': {
        'ENGINE':'django.db.backends.sqlite3',
        'NAME':BASE_DIR/'db.sqlite3',
    }
}

Models.py file for extra context:

from django.db import models
from django.contrib.auth.models import User
from cloudinary.models import CloudinaryField


class Image(models.Model):

    def __str__(self):
        return  f"Image {self.id}"

    def get_upload_to(self, instance, filename):

        if isinstance(instance, Product):
            return f'products/{instance.id}/{filename}'  # Folder for products
        elif isinstance(instance, Blog):
            return f'blogs/{instance.id}/{filename}'  # Folder for blogs
        elif isinstance(instance, Event):
            return f'events/{instance.id}/{filename}'
        elif isinstance(instance, Impact):
            return f'impacts/{instance.id}/{filename}'
        elif isinstance(instance, Job):
            return f'jobs/{instance.id}/{filename}'
        else:
            return f'services/{instance.id}/{filename}'


    file = CloudinaryField('image', folder=get_upload_to)  # Cloudinary field for each image


class MembershipTier(models.Model):
    name = models.CharField(max_length=100)
    price = models.FloatField()  #could also use DecimalField
    features = models.JSONField()  #array of strings
    description = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    is_active = models.BooleanField(default=True)

    def __str__(self):
        return self.name


class Organisation(models.Model):
    name = models.CharField(max_length=255)
    about = models.TextField()
    website = models.URLField()
    email = models.EmailField()
    facebook = models.URLField(blank=True, null=True)
    instagram = models.URLField(blank=True, null=True)
    twitter = models.URLField(blank=True, null=True)
    membership_tier = models.ForeignKey(MembershipTier, on_delete=models.SET_NULL, null=True, blank=True)
    leadership_type = models.CharField(max_length=100)
    location = models.CharField(max_length=255)
    legal_structure = models.CharField(max_length=100)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    beneficiaries = models.JSONField(blank=True, null=True)
    keywords = models.JSONField(blank=True, null=True)
    is_active = models.BooleanField(default=True)

    def __str__(self):
        return self.name


class Service(models.Model):
    organisation = models.ForeignKey(Organisation, on_delete=models.CASCADE)
    title = models.CharField(max_length=100)
    images = models.ManyToManyField(Image, blank=True)  # Link to multiple images
    description = models.TextField()

    def __str__(self):
        return self.title

class Product(models.Model):
    name = models.CharField(max_length=100)
    type = models.CharField(max_length=50)
    description = models.TextField()
    images = models.ManyToManyField(Image, blank=True)  # Link to multiple images
    organisation = models.ForeignKey(Organisation, on_delete=models.CASCADE)
    sizes = models.JSONField(blank=True, null=True)  #array of ints, could be array of strings
    is_active = models.BooleanField(default=True)

    def __str__(self):
        return self.name


class Profile(models.Model):
    #in-built django user includes username, email, password already
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    full_name = models.CharField(max_length=255, blank=True)
    is_active = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.user.username


class Blog(models.Model):
    organisation = models.ForeignKey(Organisation, on_delete=models.CASCADE)
    title = models.CharField(max_length=255)
    images = models.ManyToManyField(Image, blank=True)  # Link to multiple images
    text = models.TextField()
    created_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
    posted_at = models.DateTimeField()
    updated_at = models.DateTimeField()

    def __str__(self):
        return self.title


class Impact(models.Model):
    organisation = models.ForeignKey(Organisation, on_delete=models.CASCADE)
    title = models.CharField(max_length=255)
    funders = models.JSONField(blank=True, null=True)
    beneficiaries = models.JSONField(blank=True, null=True)
    images = models.ManyToManyField(Image, blank=True)  # Link to multiple images
    impact_report = models.TextField()
    is_active = models.BooleanField(default=True)

    def __str__(self):
        return self.title


class Event(models.Model):
    holder = models.CharField(max_length=255, default="Wild n' Kind")
    organisation = models.ForeignKey(Organisation, on_delete=models.CASCADE)
    event_link = models.URLField()
    date = models.DateField()
    time = models.TimeField(blank=True, null=True)
    title = models.CharField(max_length=255)
    field = models.CharField(max_length=50)
    is_active = models.BooleanField(default=True)

    def __str__(self):
        return self.title


class Job(models.Model):
    organisation = models.ForeignKey(Organisation, on_delete=models.CASCADE)
    title = models.CharField(max_length=255)
    description = models.TextField()
    salary = models.FloatField(blank=True, null=True)
    closing_date = models.DateField()
    opening_date = models.DateField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    is_active = models.BooleanField(default=True)
    url = models.URLField(blank=True, null=True)
    images = models.ManyToManyField(Image, blank=True)  # Link to multiple images
    yt_vid = models.URLField(blank=True, null=True)

    def __str__(self):
        return self.title

If I have provided insufficient information please let me know, any advice would be extremely appreciated!

Extra Context:

I am using a python environment that is based on python 3.12, with extra packages being installed based on this requirements.txt file:

asgiref==3.8.1
Django==5.1.3
sqlparse==0.5.2
tzdata==2024.2
cloudinary==1.41.0
django-cloudinary-storage==0.3.0

setuptools==75.5.0
wheel==0.44.0

python-dotenv==1.0.1

When you get an error, you should always copy paste the error in full.

Sorry, I have added the error trace here, it occurs when i attempt to migrate

Traceback (most recent call last):
File “/Users/abhishekshadakshari/Documents/sh22-main/WildAndKind/manage.py”, line 22, in
main()
File “/Users/abhishekshadakshari/Documents/sh22-main/WildAndKind/manage.py”, line 18, in main
execute_from_command_line(sys.argv)
File “/Users/abhishekshadakshari/Documents/sh22-main/env/lib/python3.12/site-packages/django/core/management/init.py”, line 442, in execute_from_command_line
utility.execute()
File “/Users/abhishekshadakshari/Documents/sh22-main/env/lib/python3.12/site-packages/django/core/management/init.py”, line 436, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File “/Users/abhishekshadakshari/Documents/sh22-main/env/lib/python3.12/site-packages/django/core/management/base.py”, line 413, in run_from_argv
self.execute(*args, **cmd_options)
File “/Users/abhishekshadakshari/Documents/sh22-main/env/lib/python3.12/site-packages/django/core/management/base.py”, line 459, in execute
output = self.handle(*args, **options)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “/Users/abhishekshadakshari/Documents/sh22-main/env/lib/python3.12/site-packages/django/core/management/base.py”, line 107, in wrapper
res = handle_func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “/Users/abhishekshadakshari/Documents/sh22-main/env/lib/python3.12/site-packages/django/core/management/commands/migrate.py”, line 118, in handle
executor = MigrationExecutor(connection, self.migration_progress_callback)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “/Users/abhishekshadakshari/Documents/sh22-main/env/lib/python3.12/site-packages/django/db/migrations/executor.py”, line 18, in init
self.loader = MigrationLoader(self.connection)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “/Users/abhishekshadakshari/Documents/sh22-main/env/lib/python3.12/site-packages/django/db/migrations/loader.py”, line 58, in init
self.build_graph()
File “/Users/abhishekshadakshari/Documents/sh22-main/env/lib/python3.12/site-packages/django/db/migrations/loader.py”, line 235, in build_graph
self.applied_migrations = recorder.applied_migrations()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “/Users/abhishekshadakshari/Documents/sh22-main/env/lib/python3.12/site-packages/django/db/migrations/recorder.py”, line 89, in applied_migrations
if self.has_table():
^^^^^^^^^^^^^^^^
File “/Users/abhishekshadakshari/Documents/sh22-main/env/lib/python3.12/site-packages/django/db/migrations/recorder.py”, line 63, in has_table
with self.connection.cursor() as cursor:
^^^^^^^^^^^^^^^^^^^^^^^^
File “/Users/abhishekshadakshari/Documents/sh22-main/env/lib/python3.12/site-packages/django/utils/asyncio.py”, line 26, in inner
return func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^
File “/Users/abhishekshadakshari/Documents/sh22-main/env/lib/python3.12/site-packages/django/db/backends/base/base.py”, line 320, in cursor
return self._cursor()
^^^^^^^^^^^^^^
File “/Users/abhishekshadakshari/Documents/sh22-main/env/lib/python3.12/site-packages/django/db/backends/dummy/base.py”, line 20, in complain
raise ImproperlyConfigured(
django.core.exceptions.ImproperlyConfigured: settings.DATABASES is improperly configured. Please supply the ENGINE value. Check settings documentation for more details.

This type of error is frequently caused by one of a couple different types of errors in the settings.py file.

You will need to verify your complete settings.py file for any syntax errors anywhere within that file. (Or, you can post the complete and unedited file here, if you would like for us to help you find the issue.)

This is the full unedited settings.py file, I have been looking over this and the models.py file extensively and am really stumped.

"""
Django settings for WildAndKind project.

Generated by 'django-admin startproject' using Django 5.1.2.

For more information on this file, see
https://docs.djangoproject.com/en/5.1/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.1/ref/settings/
"""

from cloudinary_storage.storage import MediaCloudinaryStorage
from pathlib import Path
from dotenv import load_dotenv
import cloudinary
import cloudinary.uploader
import cloudinary.api
import os

load_dotenv()


cloudinary.config(
    cloud_name=os.getenv('CLOUDINARY_CLOUD_NAME'),
    api_key=os.getenv('CLOUDINARY_API_KEY'),
    api_secret=os.getenv('CLOUDINARY_API_SECRET')
)

DEFAULT_FILE_STORAGE = 'cloudinary_storage.storage.MediaCloudinaryStorage'
MEDIA_URL = '/media/'


# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-@9q20b+&0ajldx#1r)y=assdkpfblvxf0@&gc!ul!&a5=hjimo'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'api.apps.ApiConfig',
    'cloudinary',
    'cloudinary_storage',
    'api',
    'WildAndKind',
    #Custom apps
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'WildAndKind.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR,'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'WildAndKind.wsgi.application'


# Database
# https://docs.djangoproject.com/en/5.1/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE':'django.db.backends.sqlite3',
        'NAME':BASE_DIR/'db.sqlite3',
    }
}

# Password validation
# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/5.1/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.1/howto/static-files/

STATIC_URL = 'static/'

STATIC_ROOT = os.path.join(BASE_DIR, 'static')

STATICFILES_DIRS = [os.path.join(BASE_DIR,'staticfiles'),
                     
                    ]
MEDIA_ROOT = os.path.join(BASE_DIR,'media')

# Default primary key field type
# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

You’re correct, there’s no syntax error here.

However, I do see where in your INSTALLED_APPS you have entries for both api and api.apps.ApiConfig. If you’ve got your api app configured in api.apps.ApiConfig, then you want to remove that duplicate setting.

If that doesn’t help, verify that your cloudinary.config call works without error

  • Run a manage.py check command
    • If this shows an error, remove everything related to cloudinary and try again.
env) (base) abhishekshadakshari@Abhisheks-MacBook-Pro-2 WildAndKind % python manage.py check
System check identified no issues (0 silenced).

Unfortunately i really am clueless here, I removed the extra api reference in INSTALLED_APPS and ran this command without removing the cloudinary settings

So after running check, what happens if you try to migrate again?

env) (base) abhishekshadakshari@Abhisheks-MacBook-Pro-2 WildAndKind %     python manage.py migrate
Traceback (most recent call last):
  File "/Users/abhishekshadakshari/Documents/sh22-main/WildAndKind/manage.py", line 22, in <module>
    main()
  File "/Users/abhishekshadakshari/Documents/sh22-main/WildAndKind/manage.py", line 18, in main
    execute_from_command_line(sys.argv)
  File "/Users/abhishekshadakshari/Documents/sh22-main/env/lib/python3.12/site-packages/django/core/management/__init__.py", line 442, in execute_from_command_line
    utility.execute()
  File "/Users/abhishekshadakshari/Documents/sh22-main/env/lib/python3.12/site-packages/django/core/management/__init__.py", line 436, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/Users/abhishekshadakshari/Documents/sh22-main/env/lib/python3.12/site-packages/django/core/management/base.py", line 413, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/Users/abhishekshadakshari/Documents/sh22-main/env/lib/python3.12/site-packages/django/core/management/base.py", line 459, in execute
    output = self.handle(*args, **options)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/abhishekshadakshari/Documents/sh22-main/env/lib/python3.12/site-packages/django/core/management/base.py", line 107, in wrapper
    res = handle_func(*args, **kwargs)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/abhishekshadakshari/Documents/sh22-main/env/lib/python3.12/site-packages/django/core/management/commands/migrate.py", line 118, in handle
    executor = MigrationExecutor(connection, self.migration_progress_callback)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/abhishekshadakshari/Documents/sh22-main/env/lib/python3.12/site-packages/django/db/migrations/executor.py", line 18, in __init__
    self.loader = MigrationLoader(self.connection)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/abhishekshadakshari/Documents/sh22-main/env/lib/python3.12/site-packages/django/db/migrations/loader.py", line 58, in __init__
    self.build_graph()
  File "/Users/abhishekshadakshari/Documents/sh22-main/env/lib/python3.12/site-packages/django/db/migrations/loader.py", line 235, in build_graph
    self.applied_migrations = recorder.applied_migrations()
                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/abhishekshadakshari/Documents/sh22-main/env/lib/python3.12/site-packages/django/db/migrations/recorder.py", line 89, in applied_migrations
    if self.has_table():
       ^^^^^^^^^^^^^^^^
  File "/Users/abhishekshadakshari/Documents/sh22-main/env/lib/python3.12/site-packages/django/db/migrations/recorder.py", line 63, in has_table
    with self.connection.cursor() as cursor:
         ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/abhishekshadakshari/Documents/sh22-main/env/lib/python3.12/site-packages/django/utils/asyncio.py", line 26, in inner
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/Users/abhishekshadakshari/Documents/sh22-main/env/lib/python3.12/site-packages/django/db/backends/base/base.py", line 320, in cursor
    return self._cursor()
           ^^^^^^^^^^^^^^
  File "/Users/abhishekshadakshari/Documents/sh22-main/env/lib/python3.12/site-packages/django/db/backends/dummy/base.py", line 20, in complain
    raise ImproperlyConfigured(
django.core.exceptions.ImproperlyConfigured: settings.DATABASES is improperly configured. Please supply the ENGINE value. Check settings documentation for more details.

Exact same trace, I’m sorry I really don’t know whats going on

And this is with removing all of the “cloudinary” configuration?

DJANGO_SETTINGS_MODULE is normally set inside manage.py, so this seems strange to me. Could you verify that it is indeed set there?

It was, somehow when i reverted my models and settings to not use cloudinary, then re-added the cloudinary code it worked, I’m just not sure if it’ll stay working, I’ll add my manage.py file below, but ye its sorted for now

#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys


def main():
    """Run administrative tasks."""
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'WildAndKind.settings')
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        raise ImportError(
            "Couldn't import Django. Are you sure it's installed and "
            "available on your PYTHONPATH environment variable? Did you "
            "forget to activate a virtual environment?"
        ) from exc
    execute_from_command_line(sys.argv)


if __name__ == '__main__':
    main()