I borrowed ideas from this answer to extend the default Site object created during the initial migration with Django sites framework. The new model, SiteSettings, establishes a OneToOne relationship with the Site model to add additional fields. I then use signals to create the SiteSettings object.
When I made the first migration for the SiteSettings model everything appeared to work fine. A SiteSettings object was created that had a OneToOne relationship with the default Site object.
However, what I didn't notice is that a migration file wasn't created under my local app for this. I was able to makemigrations and migrate just fine, so I'm not sure where that migration went. It's not listed in my migrations table.
Anyway, since it worked I didn't notice. I then proceeded to add additional fields to SiteSettings a day or two later, and noticed when I made those migrations, they were for creating a SiteSettings model, not updating its fields. That's when I noticed that the first migration wasn't created in the right spot. The second migration was created, however it was created in site-packages/django/contrib/sites/migrations/
. It looks like this:
class Migration(migrations.Migration):
dependencies = [
("sites", "0002_alter_domain_unique"), # the initial auto migration
]
operations = [
migrations.CreateModel(
name="SiteSettings",
fields=[
(
"site",
models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
primary_key=True,
related_name="settings",
serialize=False,
to="sites.site",
verbose_name="site",
),
),
# A bunch of other CharFields that aren't important
],
options={
"verbose_name_plural": "settings",
},
),
]
And my models.py looks like this. I'm assuming the issue may be with the app_label
matching the name of django.contrib.sites
, but I'm not sure. The reason I named the label that was so it shows up under sites in the admin.
class SiteSettings(models.Model):
"""
Extension of the Sites model that holds more info about the site.
"""
site = models.OneToOneField(
Site,
on_delete=models.CASCADE,
primary_key=True,
related_name="settings",
verbose_name="site",
)
# A bunch of other fields that aren't important
def __str__(self):
return self.site.name
class Meta:
app_label = "sites"
verbose_name_plural = "settings"
Here's what the apps.py looks like:
from django.apps import AppConfig
from django.conf import settings
from django.db.models.signals import post_migrate, post_save
def create_default_site_settings(sender, **kwargs):
"""Creates default site settings after migration"""
# App config must be ready for import to work
from django.contrib.sites.models import Site
from .models import SiteSettings
site = Site.objects.get(id=getattr(settings, "SITE_ID", 1))
if not SiteSettings.objects.exists():
SiteSettings.objects.create(site=site)
class CoreConfig(AppConfig):
name = "apps.core"
label = "core"
default_auto_field = "django.db.models.BigAutoField"
def ready(self):
# App config must be ready for import to work
from django.contrib.sites.models import Site
post_migrate.connect(create_default_site_settings, sender=self)
from .signals import create_site_settings
post_save.connect(create_site_settings, sender=Site)
And lastly, signals.py.
from django.contrib.sites.models import Site
from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import SiteSettings
@receiver(post_save, sender=Site)
def create_site_settings(sender, instance, **kwargs):
"""
Creates/updates a SiteSettings object after a Site object.
"""
site_settings, created = SiteSettings.objects.update_or_create(site=instance)
if not created:
site_settings.save()
Is this simply an issue with the app_label
being the same? I'm trying to wrap my head around why that is if so.
app_label
resolves the issue with migrations? Is there an issue with removing it? – Ortiz