Using a django model to store "constant"

I am using a django model to store start date and end date for the date rate I want to be active for the whole project. There can exist activities in my project outside the date range and these are the ones I want filtered out in all my views.

Is there a way to use this model (I call it GlobalDateSettings) as a sort of a constant, singleton or the like, so I can only ever change it and not make new instances, since I only ever want one start date, and one end date?

Right now I am using kind of a workaround via the Model.objects.first() but I am thinking there must be a more Django-standard or pythonic way?

Donā€™t know if it helps, but my models is:

class GlobalDateSettings(models.Model):
    start_date = models.DateField()
    end_date = models.DateField()

    def save(self, *args, **kwargs):
        if not self.pk and GlobalDateSettings.objects.exists():
            raise ValidationError("There can only be one instance of GlobalDateSettings")
        return super(GlobalDateSettings, self).save(*args, **kwargs)

My question is two-fold, but I split the debate into two separate posts - other one is here
https://forum.djangoproject.com/t/trying-to-dry-my-django-code/28891

Can you physically prevent the addition of new rows?
Only if you implement a trigger in the database to prevent new rows from being added.

However, if you limit your concerns to what is done in Django, itā€™s a lot easier.

If you donā€™t write any code that inserts into that model, then youā€™re never going to add rows. If you need to prevent the admin from adding rows, you can do that, too.

Django doesnā€™t just go around adding rows to models - if a row is being added, itā€™s because there is code to do that. So donā€™t do that.

1 Like

Yes. I can see now, that I can limit it to an UpdateView only accessible to the admin user. Thank you.

Is creating a model to only ever store one instance of ā€œproject settingsā€ like this ā€œModel.objects.first()ā€ the preferred way or am I missing something?

We do a couple different things simiar to this depending upon need.

Itā€™s rare for us to only have one value that needs to be set as a project-level setting. So one of the things we do is create a Settings model.
This model has a field for the setting name, and fields for a charfield, boolean, integer and Decimal. The setting name is the primary key, ensuring that thereā€™s only one instance in the model with that name, and only one of the data fields gets populated.

1 Like

Could you show code pls?

Not really much to show.

class Settings(models.Model):
    name = models.CharField(man_length=20, primary_key=True)
    char_val = models.CharField(max_length=100, blank=True, null=True, default=None)
    int_val = models.IntegerField(blank=True, null=True, default=None)
    bool_val = models.BooleanField(blank=True, null=True, default=None)
    dec_val = models.DecimalField(max_digits=11, decimal_places=2, blank=True, null=True, default=None)
1 Like

And how would you use it as you said ā€œnamed settingā€ in your views?

Itā€™s a model. You use it exactly the same way you use any other model.

I was thinking about how it looks in a view or templateā€¦ I will try it and get back here after

Is this close to how you would do it?
https://www.rootstrap.com/blog/simple-dynamic-settings-for-django

No.

Our approach uses one row for each setting. Adding a new setting means we just add an additional row.

That approach is creating one row in a model for all the individual settings. Adding a new setting requires modifying the model itself.

Just for checking if I get it. You mean like settings[ā€˜new_settingā€™] = new_value
for instance:
settings[ā€˜darkmodeā€™] = True

and then later doing something like
settting_obj = settings.objects.first()ā€¦
darkmode = setting_obj.darkmode
if darkmode:
do dark color stuff here

Right?

No. Thereā€™s one row for each setting. That setting is identified by the field name. Only one of the _val fields get populated for each row, the other fields remain null.

To use your example, weā€™d need to extend our Settings model to add a date field. (We donā€™t have any settings needing a date, so we donā€™t have it in our model.)
date_val = models.DateField(...)

To create your example, it would be something like:
Settings.objects.create(name=ā€œstart_dateā€, date_val=ā€˜2024-03-01ā€™)
Settings.objects.create(name=ā€œend_dateā€, date_val=ā€˜2024-03-31ā€™)

1 Like