[Django] String Labels in Site: Use Key-Value Pairs Model & Form

This article is to make a model used to save string label in site (e.g. site_title), like this:

1
2
3
class Label(models.Model):
key = models.CharField(max_length=32, primary_key=True)
value = models.CharField(max_length=128,blank=True, default='')

And, make a form like this to update it:

1
2
3
4
5
6
7
Site Configuration
site_title: ________________
site_subtitle: _________________
site_copyright_info: _________________
admin_email: _________________
admin_phone: _________________
[Save]

There are some package like jezdez/django-constance to do this task, but I would rather not to use too many 3rd part package in project. Though, I use django-crispy-forms.

settings.py

Define your labels in settings.py:

1
2
3
4
5
6
LABELS = [
# ('key', 'label in form', 'default value'),
('site_title' , 'Site Title', 'Hello World!'),
('copyright_info' , 'Copyright Info', 'John Smith (c) 2015'),
('admin_email' , 'Your E-mail', '02 1234 5678'),
]

models.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from django.conf import settings
from django.db import models

class Label(models.Model):
key = models.CharField(max_length=32, primary_key=True)
value = models.CharField(max_length=128,blank=True, default='')

@classmethod
def get_label(cls, key):

"""Get the value of a label via key.
If not found, create one with the default value in
settings.LABELS."""

try:
return cls.objects.get(key=key).value
except:
default_value = [x for x in settings.LABELS if x[0] == key][0]
cls.objects.create(key=key, value=default_value)
return default_value

forms.py

We define save() method to save request.POST into our model.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from django import forms
from pages.models import Label
from django.conf import settings

from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit, Layout, Div, Button, Fieldset, HTML

class LabelForm(forms.Form):

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for key, label, default_value in settings.LABELS: # settings.LABELS
self.fields[key] = forms.CharField(max_length=128)
self.fields[key].label = label

# get_or_create => (<Label: Label object>, False)
labelObj, _ = Label.objects.get_or_create(
key=key,
defaults={'value': default_value})
self.fields[key].initial = labelObj.value

self.helper = FormHelper()
self.helper.add_input(Submit('submit', 'Submit'))

def save(self, POST):
for key, _, _ in settings.LABELS:
Label.objects.filter(key=key).update(value=POST[key])

views.py

1
2
3
4
5
6
7
8
9
10
11
12
13
from pages.models import Label
from pages.forms import LabelForm

class LabelSettings(FormView):

template_name = "label_settings.html"
form_class = LabelForm
success_url = '.' # whatever.

def form_valid(self, form):
super().form_valid(form)
form.save(self.request.POST) # pass POST dict to LabelForm.save()
return HttpResponseRedirect(self.get_success_url())

label_settings.html

This page is used to edit/save our labels.

1
2
3
<form method="post" action="">
{% crispy form %}
</form>

How To Use In Template?

templatetags/common_tags.py

1
2
3
4
5
6
7
from django import template
from pages.models import Label
register = template.Library()

@register.simple_tag
def label(key):
return Label.get_label(key)

Now, we can use it!

1
2
{% load common_tags %}
<h1>{% label 'site_title' %}</h1>