Reputation: 4182
all! I am writing a Django blog site.
I am new to Django. Since Django has the philosophy of loose coupling, I believe it's best to follow their beliefs when using their framework.
So I am encountering a dilemma here:
I want to set up some variables for my blog, say, the blog title, slogan, and the maximum length of digest on the homepage of each blog I wrote, and how many blog digest should I display on the homepage per page.
I can do this by creating a new app in my Django project, and create models for my site's config variables, then read those variables from other app, but this practice obviously breaks the philosophy of loose coupling.
The only work around I can think of is setting up environment variables in my sites .wsgi file (I use Apache and mod_wsgi to serve Python scripts) But I don't think messing up with environment variable is 'clean' enough.
Can anyone suggest me a better solution?
Upvotes: 10
Views: 5010
Reputation: 1744
In my opinion, the best way to do this is by adding a model related to Site model using inheritance
First add site id to your Django settings file
SITE_ID = 1
now create a model in an app
from django.db import models
from django.contrib.sites.models import Site
class Settings(Site):
field_a = models.CharField(max_length=150, null=True)
field_b = models.CharField(max_length=150, null=True)
class Meta:
verbose_name_plural = 'settings'
db_table = 'core_settings' # core is name of my app
def __str__(self) -> str:
return 'Settings'
then edit apps.py file of that app
from django.apps import AppConfig
from django.db.models.signals import post_migrate
def build_settings(sender, **kwargs):
from django.contrib.sites.models import Site
from .models import Settings
if Settings.objects.count() < 1:
Settings.objects.create(site_ptr=Site.objects.first())
class CoreConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'project.apps.core'
def ready(self) -> None:
post_migrate.connect(build_settings, sender=self)
now every time you run migrations a row will auto-generated in core_settings that have a one to one relationship with your Site model
and now you can access to your settings like this
Site.objects.get_current().settings.access_id
optional: if have only a single site unregister site model from admin site and disable creating and deleting settings model in admin panel
from django.contrib import admin
from . import models
from django.contrib.sites.models import Site
admin.site.unregister(Site)
@admin.register(models.Settings)
class SettingAdminModel(admin.ModelAdmin):
def has_delete_permission(self, request,obj=None) -> bool:
return False
def has_add_permission(self, request) -> bool:
return False
Upvotes: 0
Reputation: 3160
First thing you can do is set up those variables in your project's settings module, many apps do that:
# settings
BLOG_TITLE = 'My title'
Then, a good practice is to provide settings defaults, so your app should have a settings file
# blog/settings.py
from django.conf import settings
BLOG_TITLE = getattr(settings, 'BLOG_TITLE', 'MY default title')
# Then wherever, views or context processor
from blog import settings # See how we're not importing project's settings
title = settings.BLOG_TITLE
Another alternative is to create a "Blog" model that contains all those variables, this may invite you to make your app to have a blog tied per Django sites
from django.contrib.sites.models import Site
class Blog(models.Model):
site = models.OneToOneField(Site) # Tied up to a Django site
title = models.CharField(max_length=256)
Now you can change those values from your Admin interface and use them in your views or context processor
site = Site.objects.get_current() # Installed Django Sites app and middleware
blog = site.blog
print blog.title
Upvotes: 10
Reputation: 45922
You can create settings or constants file in your app folder and use it. This way all your constants will be bound to your application:
apps/
blog/
__init__.py
models.py
urls.py
constants.py # <-- here it is!
File can look like this:
BLOG_TITLE = 'My super blog'
# ...
And you can use tour constants like this:
import blog.constants
# ...
return render_to_response('index.html', {title: blog.constants.BLOG_TITLE})
And in template:
<title>{{ title }}</title>
Upvotes: 4