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