Helps working with singletons - things like global settings that you want to edit from the admin site.

Related tags

Djangodjango-solo
Overview

Django Solo

+---------------------------+
|                           |
|                           |
|             \             | Django Solo helps working with singletons:
|             /\            | database tables that only have one row.
|           >=)'>           | Singletons are useful for things like global
|             \/            | settings that you want to edit from the admin
|             /             | instead of having them in Django settings.py.
|                           | 
|                           | 
+---------------------------+

Features

Solo helps you enforce instantiating only one instance of a model in django.

  • You define the model that will hold your singleton object.
  • django-solo gives helper parent class for your model and the admin classes.
  • You get an admin interface that's aware you only have one object.
  • You can retrieve the object from templates.
  • By enabling caching, the database is not queried intensively.

Use Cases

Django Solo is also great for use with singleton objects that have a one to many relationship. Like the use case below where you have a 'Home Slider" that has many "Slides".

  • Global or default settings
  • An image slider that has many slides
  • A page section that has sub-sections
  • A team bio with many team members

There are many cases where it makes sense for the parent in a one to many relationship to be limited to a single instance.

Usage Example

# models.py

from django.db import models
from solo.models import SingletonModel

class SiteConfiguration(SingletonModel):
    site_name = models.CharField(max_length=255, default='Site Name')
    maintenance_mode = models.BooleanField(default=False)

    def __str__(self):
        return "Site Configuration"

    class Meta:
        verbose_name = "Site Configuration"
# admin.py

from django.contrib import admin
from solo.admin import SingletonModelAdmin
from config.models import SiteConfiguration

admin.site.register(SiteConfiguration, SingletonModelAdmin)

# There is only one item in the table, you can get it this way:
from .models import SiteConfiguration
config = SiteConfiguration.objects.get()

# get_solo will create the item if it does not already exist
config = SiteConfiguration.get_solo()

In your model, note how you did not have to provide a verbose_name_plural field - That's because Django Solo uses the verbose_name instead.

If you're changing an existing model (which already has some objects stored in the database) to a singleton model, you can explicitly provide the id of the row in the database for django-solo to use. This can be done by setting singleton_instance_id property on the model:

class SiteConfiguration(SingletonModel):
    singleton_instance_id = 24
    # (...)

Installation

This application requires Django >= 1.6.

  • Install the package using pip install django-solo
  • Add solo or solo.apps.SoloAppConfig to your INSTALLED_APPS setting.

This is how you run tests:

./manage.py test solo --settings=solo.tests.settings

Supported Languages

  • English
  • Spanish

Admin

The standard Django admin does not fit well when working with singleton, for instance, if you need some global site settings to be edited in the admin. Django Solo provides a modified admin for that.

django-solo admin

  • In the admin home page where all applications are listed, we have a config application that holds a singleton model for site configuration.
  • The configuration object can only be changed, there's no link for "add" (1).
  • The link to the configuration page (2) directly goes to the form page - no need for an intermediary object list page, since there's only one object.
  • The edit page has a modified breadcrumb (3) to avoid linking to the intermediary object list page.
  • From the edit page, we cannot delete the object (4) nor can we add a new one (5).

If you wish to disable the skipping of the object list page, and have the default breadcrumbs, you should set SOLO_ADMIN_SKIP_OBJECT_LIST_PAGE to False in your settings.

Availability from templates

The singleton object can be retrieved from template by giving the Django model dotted path:

{% get_solo 'app_label.ModelName' as my_config %}

Example:

{% load solo_tags %}
{% get_solo 'config.SiteConfiguration' as site_config %}
{{ site_config.site_name }}
{{ site_config.maintenance_mode }}

If you're extending a template, be sure to use the tag in the proper scope.

Right:

{% extends "index.html" %}
{% load solo_tags %}

{% block content %}
    {% get_solo 'config.SiteConfiguration' as site_config %}
    {{ site_config.site_name }}
{% endblock content %}

Wrong:

{% extends "index.html" %}
{% load solo_tags %}
{% get_solo 'config.SiteConfiguration' as site_config %}

{% block content %}
    {{ site_config.site_name }}
{% endblock content %}

Caching

By default caching is disabled: every time get_solo retrieves the singleton object, there will be a database query.

You can enable caching to only query the database when initially retrieving the object. The cache will also be updated when updates are made from the admin.

The cache timeout is controlled via the SOLO_CACHE_TIMEOUT settings. The cache backend to be used is controlled via the SOLO_CACHE settings.

Settings

Template tag name

You can retrieve your singleton object in templates using the get_solo template tag.

You can change the name get_solo using the GET_SOLO_TEMPLATE_TAG_NAME setting.

GET_SOLO_TEMPLATE_TAG_NAME = 'get_config'

Admin override flag

By default, the admin is overridden. But if you wish to keep the object list page (e.g. to customize actions), you can set the SOLO_ADMIN_SKIP_OBJECT_LIST_PAGE to False.

SOLO_ADMIN_SKIP_OBJECT_LIST_PAGE = True

Cache backend

Django provides a way to define multiple cache backends with the CACHES settings. If you want the singleton object to be cached separately, you could define the CACHES and the SOLO_CACHE settings like this:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': '127.0.0.1:11211',
    },
    'local': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
    },
}

SOLO_CACHE = 'local'

Caching will be disabled if set to None.

Cache timeout

The cache timeout in seconds.

SOLO_CACHE_TIMEOUT = 60*5  # 5 mins

Cache prefix

The prefix to use for the cache key.

SOLO_CACHE_PREFIX = 'solo'

Getting the code

The code is hosted at https://github.com/lazybird/django-solo/

Check out the latest development version anonymously with:

$ git clone git://github.com/lazybird/django-solo.git

You can install the package in the "editable" mode like this:

pip uninstall django-solo  # just in case...
pip install -e git+https://github.com/lazybird/django-solo.git#egg=django-solo

You can also install a specific branch:

pip install -e git+https://github.com/lazybird/[email protected]#egg=django-solo

The package is now installed in your project and you can find the code.

Comments
  • Django 1.9 will remove get_cache support

    Django 1.9 will remove get_cache support

    https://docs.djangoproject.com/en/1.7/topics/cache/#django.core.cache.get_cache

    In order to support future django releases we need to remove usage of that feature and convert to using https://docs.djangoproject.com/en/1.7/topics/cache/#django.core.cache.caches

    opened by Harper04 10
  • Support django-rest-framework by providing ViewSets

    Support django-rest-framework by providing ViewSets

    A ReadOnlyModelViewSet and ModelViewSet like would be great. (more info at http://www.django-rest-framework.org/api-guide/viewsets/)

    This is as far I could get:

    from rest_framework import mixins, viewsets
    
    
    class ReadOnlySingletonViewSet(
            mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    
        def get_object(self):
            obj = self.model.get_solo()
            self.check_object_permissions(self.request, obj)
            return obj
    

    It is ok but I have to provide a pk argument to the URL as following:

    /api/<resource-prefix>/<pk>/

    can be any value. Would be great if we could get rid of this parameter.

    feature request 
    opened by semente 10
  • Django 4.0 Support

    Django 4.0 Support

    Closes #76

    Closes #108

    #104 instates the policy for supporting supported Django versions and thus this PR is compatible with that new policy.

    • Officially support Django 2.2, 3.2, and 4.0, the versions of Django currently supported
    • Do not require Django to be installed simply to build the source distribution for django-solo. This enables testing to work when only tox is installed (e.g. CI)
    bug 
    opened by johnthagen 8
  • django.template.exceptions.TemplateDoesNotExist: admin/solo/change_form.html

    django.template.exceptions.TemplateDoesNotExist: admin/solo/change_form.html

    Hi!

    When I go to my singleton model's admin change page, I get the exception django.template.exceptions.TemplateDoesNotExist: admin/solo/change_form.html. I'm working with Django 3.1.1.

    The problem is that the egg file of the package is a zip file and not a directory (the extraction did not happen). But Django's default template loader can find templates in directories only: https://github.com/django/django/blob/0b8871ab6744285943784795ede053839ee009ef/django/template/utils.py#L94

    To force the unzip, you need to set the zip-safe option to False: https://setuptools.readthedocs.io/en/latest/formats.html#zip-safe-and-not-zip-safe. You can do so in the setup.py file:

    # ...
    setup(
        # ...
        zip_safe=False,
    )
    

    Thanks!

    bug 
    opened by Vayel 7
  • In Django 2.0 / Python 3.6 getting the error AttributeError: 'Library' object has no attribute 'assignment_tag'

    In Django 2.0 / Python 3.6 getting the error AttributeError: 'Library' object has no attribute 'assignment_tag'

    python manage.py test solo --settings=solo.tests.settings

    ...... site-packages/solo/templatetags/solo_tags.py", line 16, in @register.assignment_tag(name=solo_settings.GET_SOLO_TEMPLATE_TAG_NAME) AttributeError: 'Library' object has no attribute 'assignment_tag'

    opened by mohamed-osama-aboelkheir 7
  • Publish 2.0.0 to PyPI (Django 4.0)

    Publish 2.0.0 to PyPI (Django 4.0)

    @lazybird Could you please release a new sdist and wheel to PyPI for the 2.0.0 release? This is required to allow Django 4.0 users to use django-solo.

    To create a wheel along with source distribution:

    (venv) $ python -m pip install --upgrade pip setuptools wheel
    (venv) $ python setup.py sdist bdist_wheel
    
    # See dist/*.whl
    

    To upload sdist and wheel:

    (venv) $ pip install twine
    (venv) $ twine upload dist/*
    
    opened by johnthagen 5
  • verbose_name_plural for SingletonModelAdmin

    verbose_name_plural for SingletonModelAdmin

    Can you add in so that if the model is a SingletonModelAdmin, the name that is displayed in the admin is the verbose_name instead of the verbose_name_plural ?

    opened by radzhome 5
  • Django 4.x deprecation errors (ugettext + force_text)

    Django 4.x deprecation errors (ugettext + force_text)

    Upgrading to Django 3.x and using Django-Solo 1.1.3 raise these deprecations:

    solo/admin.py:53: RemovedInDjango40Warning: django.utils.translation.ugettext() 
    is deprecated in favor of django.utils.translation.gettext().
        msg = _('%(obj)s was changed successfully.') % {'obj': force_unicode(obj)}
    
    solo/admin.py:53: RemovedInDjango40Warning: force_text()
     is deprecated in favor of force_str().
        msg = _('%(obj)s was changed successfully.') % {'obj': force_unicode(obj)}
    

    It will take a while before Django 4.x is here, so no need to rush yet. I'll have a look if I'm able to create a PR myself.

    bug 
    opened by dennissiemensma 4
  • Crash on migrations

    Crash on migrations

    I have an issue with running manage.py migrate - it tries to run ModelName.get_solo() method and fails with database error.

    App structure: --- models.py --- helpers/ ----- bot.py

    In bot.py I'm doing:

    from appname.models import ModelName
    config = ModelName.get_solo()
    

    How to prevent execution of ModelName.get_solo() while manage.py migrate ?

    opened by deusesx 4
  • django-reversion integration

    django-reversion integration

    Usecase

    I want to have a singleton object with versions.

    Integration

    At first the were several issues with integrating it all together.

    reversion/admin.py:

    def change_view(self, request, object_id, form_url='', extra_context=None):
            with self.create_revision(request):
                # ugly hack to make it work:
                return admin.ModelAdmin.change_view(self, request, object_id, form_url, extra_context)
    

    solo/admin.py:

        def change_view(self, request, object_id, extra_context=None, form_url='/'):
            if object_id == '1':
                self.model.objects.get_or_create(pk=1)
            return super(SingletonModelAdmin, self).change_view(
                request,
                object_id,
                form_url=form_url,  # this parameter was required
                extra_context=extra_context,
            )
    

    and my own admin.py:

    from solo.admin import SingletonModelAdmin
    from reversion.admin import VersionAdmin
    
    class MyModelAdmin(VersionAdmin, SingletonModelAdmin):
        pass  # it does not work with `MyModelAdmin(SingletonModelAdmin, VersionAdmin)`
    
    admin.site.register(Document, MyModelAdmin)
    

    TODO

    1. I have not tried to run any tests
    2. Ugly hack with admin.ModelAdmin.change_view(self, ...) should be changed
    3. Any other things to keep in mind?

    Demo

    2016-06-26 14 41 04

    2016-06-26 14 40 56

    2016-06-26 14 40 49
    opened by sobolevn 4
  • TemplateDoesNotExist  admin/solo/change_form.html

    TemplateDoesNotExist admin/solo/change_form.html

    I'm working on django 1.7.5 with django-suit, the error occurs access my singleton model.

    I corrected this error by commenting the line # 13 admin.py: change_form_template = "admin / solo / change_form.html"

    TemplateDoesNotExist at /admin/config/siimciconfig/

    admin/solo/change_form.html

    Request Method: GET Request URL: http://localhost:8000/admin/config/siimciconfig/ Django Version: 1.7.5 Exception Type: TemplateDoesNotExist Exception Value:

    admin/solo/change_form.html

    Exception Location: /home/leon/.virtualenvs/django1.7/local/lib/python2.7/site-packages/django/template/loader.py in find_template, line 136 Python Executable: /home/leon/.virtualenvs/django1.7/bin/python Python Version: 2.7.8 Python Path:

    ['/media/ubuntu13/home/leon/django1.7/siaiepi', '/home/leon/.virtualenvs/django1.7/local/lib/python2.7/site-packages/django_solo-1.1.0-py2.7.egg', '/home/leon/.virtualenvs/django1.7/lib/python2.7/site-packages/django_solo-1.1.0-py2.7.egg', '/home/leon/.virtualenvs/django1.7/lib/python2.7', '/home/leon/.virtualenvs/django1.7/lib/python2.7/plat-x86_64-linux-gnu', '/home/leon/.virtualenvs/django1.7/lib/python2.7/lib-tk', '/home/leon/.virtualenvs/django1.7/lib/python2.7/lib-old', '/home/leon/.virtualenvs/django1.7/lib/python2.7/lib-dynload', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-x86_64-linux-gnu', '/usr/lib/python2.7/lib-tk', '/home/leon/.virtualenvs/django1.7/local/lib/python2.7/site-packages', '/home/leon/.virtualenvs/django1.7/lib/python2.7/site-packages']

    Server time: Lun, 2 Mar 2015 18:46:49 -0500

    opened by loco0321 4
  • Django migrations don't work if you use the model in code without making migrations first

    Django migrations don't work if you use the model in code without making migrations first

    if I take my existing model

    class SiteConfiguration(SingletonModel):
         site_name = models.CharField(max_length=255, default='Administration')
    

    then add to it a additional field

    class SiteConfiguration(SingletonModel):
         site_name = models.CharField(max_length=255, default='Administration')
         message = models.TextField(default="this is a standard message")
    

    then inside of django views.py

    ...
    site_config = SiteConfiguration.get_solo()
    def view(request):
          site_config.message
         return HttpResponse("some response")
    ...
    

    then try to run a migration i get a error django.db.utils.OperationalError: no such column: siteconfiguration.message

    this is a very big problem for me because I often write my code first to see how it looks first before making the migrations. Also this does work in a standard model so it should work in a SingletonModel

    opened by dragoncommits 0
  • whenever I update the model I get

    whenever I update the model I get "No such column" error

    I cant seem to update the model without getting an error when trying to makemigrations / migrate that states the field I am trying to add does not exist in the table.

    For example: models:

        maintenance_mode = models.BooleanField(default=False)
        name = models.CharField(max_length=255, default='Open Mosque Project')
        about = models.TextField(max_length=2000, blank=True) ## new field i've added ##
    

    view:

    from config.models import CentreProfile
    centre = CentreProfile.objects.get()
    ##### Variables loaded from centre profile here #####
    centre_name = centre.name 
    

    Error when I try to make migrations

    django.db.utils.OperationalError: no such column: config_centreprofile.about

    opened by bitFez 1
  • Update cache after instance save

    Update cache after instance save

    Maybe I'm missing something obvious, but is there a way to clear the cache after saving the instance directly, instead of via the form?

    We have one singleton that's updated automatically via a worker task, so doesn't go through the form. If I run this:

    sgtn = MySingleton.get_solo()
    sgtn.name = 'New Value'
    sgtn.save()
    

    and then I query the result using MySingleton.get_solo().name I get the previous value.

    I tried overriding the save method like this:

    def save(self, *args, **kwargs):
            self.clear_cache()
            super().save(*args, **kwargs)  
    

    But that didn't work either. Is there a way of configuring this? Seems like quite a reasonable use case if not.

    question 
    opened by matt-dalton 0
  • App verbose_name not used in breadcrumbs

    App verbose_name not used in breadcrumbs

    Django uses verbose_name of apps when constructing breadcrumbs. Solo doesn't :(

    django/contrib/admin/templates/admin/change_form.html:

    {{ opts.app_config.verbose_name }}
    

    solo/templates/admin/solo/change_form.html:

    {{ opts.app_label|capfirst|escape }}
    

    Should probably update the code.

    It is quite possible that some extra care has to be taken to maintain support for older versions of Django. I didn't check...

    feature request 
    opened by frnhr 1
Releases(2.0.0)
  • 2.0.0(Dec 10, 2021)

    What's Changed

    • Use assertEqual instead of assertEquals for Python 3.11 compatibility. by @tirkarthi in https://github.com/lazybird/django-solo/pull/103
    • Change package URL to use HTTPS by @johnthagen in https://github.com/lazybird/django-solo/pull/105
    • Setup automated testing using GitHub Actions by @johnthagen in https://github.com/lazybird/django-solo/pull/106
    • Django 4.0 Support by @johnthagen in https://github.com/lazybird/django-solo/pull/107
    • Release 2.0.0 by @johnthagen in https://github.com/lazybird/django-solo/pull/112

    New Contributors

    • @tirkarthi made their first contribution in https://github.com/lazybird/django-solo/pull/103

    Full Changelog: https://github.com/lazybird/django-solo/compare/1.2.0...2.0.0

    Source code(tar.gz)
    Source code(zip)
  • 1.2.0(Sep 29, 2021)

Owner
Sylvain Toé
Sylvain Toé
Django-pwned - A collection of django password validators

Django Pwned A collection of django password validators. Compatibility Python: 3

Quera 22 Jun 27, 2022
Django GUID attaches a unique correlation ID/request ID to all your log outputs for every request.

Django GUID Now with ASGI support! Django GUID attaches a unique correlation ID/request ID to all your log outputs for every request. In other words,

snok 300 Dec 29, 2022
Django Federated Login provides an authentication bridge between Django projects and OpenID-enabled identity providers.

Django Federated Login Django Federated Login provides an authentication bridge between Django projects and OpenID-enabled identity providers. The bri

Bouke Haarsma 18 Dec 29, 2020
A Django chatbot that is capable of doing math and searching Chinese poet online. Developed with django, channels, celery and redis.

Django Channels Websocket Chatbot A Django chatbot that is capable of doing math and searching Chinese poet online. Developed with django, channels, c

Yunbo Shi 8 Oct 28, 2022
User Authentication In Django/Ajax/Jquery

User Authentication In Django/Ajax/Jquery Demo: Authentication System Using Django/Ajax/Jquery Demo: Authentication System Using Django Overview The D

Suman Raj Khanal 10 Mar 26, 2022
A Django web application that shortens long URLs. This is a demo project to show off my tech abilities.

Django URL Shortener This project is just a complete and production-ready URL shortener web application to show off my tech and coding abilities. Impo

Seyyed Ali Ayati 5 Jan 26, 2022
A blog app powered by python-django

Django_BlogApp This is a blog app powered by python-django Features Add and delete blog post View someone else blog Can add comment to that blog And o

Manish Jalui 1 Sep 12, 2022
A Blog Management System Built with django

Blog Management System Backend use: Django Features Enhanced Ui

Vishal Goswami 1 Dec 06, 2021
django app that allows capture application metrics by each user individually

Django User Metrics django app that allows capture application metrics by each user individually, so after you can generate reports with aggregation o

Reiner Marquez 42 Apr 28, 2022
Django-gmailapi-json-backend - Email backend for Django which sends email via the Gmail API through a JSON credential

django-gmailapi-json-backend Email backend for Django which sends email via the

Innove 1 Sep 09, 2022
Django project starter on steroids: quickly create a Django app AND generate source code for data models + REST/GraphQL APIs (the generated code is auto-linted and has 100% test coverage).

Create Django App 💛 We're a Django project starter on steroids! One-line command to create a Django app with all the dependencies auto-installed AND

imagine.ai 68 Oct 19, 2022
Displaying objects on maps in the Django views and administration site.

DjangoAdminGeomap library The free, open-source DjangoAdminGeomap library is designed to display objects on the map in the Django views and admin site

Vitaly Bogomolov 31 Dec 28, 2022
💨 Fast, Async-ready, Openapi, type hints based framework for building APIs

Fast to learn, fast to code, fast to run Django Ninja - Fast Django REST Framework Django Ninja is a web framework for building APIs with Django and P

Vitaliy Kucheryaviy 3.8k Jan 01, 2023
Send push notifications to mobile devices through GCM or APNS in Django.

django-push-notifications A minimal Django app that implements Device models that can send messages through APNS, FCM/GCM and WNS. The app implements

Jazzband 2k Dec 26, 2022
Money fields for Django forms and models.

django-money A little Django app that uses py-moneyed to add support for Money fields in your models and forms. Django versions supported: 1.11, 2.1,

1.4k Jan 06, 2023
Exemplo de biblioteca com Django

Bookstore Exemplo de biblioteca feito com Django. Este projeto foi feito com: Python 3.9.7 Django 3.2.8 Django Rest Framework 3.12.4 Bootstrap 4.0 Vue

Regis Santos 1 Oct 28, 2021
Code coverage measurement for Python

Coverage.py Code coverage testing for Python. Coverage.py measures code coverage, typically during test execution. It uses the code analysis tools and

Ned Batchelder 2.3k Jan 05, 2023
Forward and backwards compatibility layer for Django 1.4, 1.7, 1.8, 1.9, 1.10, and 1.11

django-compat Forward and backwards compatibility layer for Django 1.4 , 1.7 , 1.8, 1.9, 1.10 and 1.11 Consider django-compat as an experiment based o

arteria GmbH 106 Mar 28, 2022
GeoDjango provides geospatial extensions to the Django web dev framework

Django is a high-level Python Web framework that encourages rapid development and clean, pragmatic design. All documentation is in the "docs" directo

Paul Smith 20 Sep 20, 2022
Application made in Django to generate random passwords as based on certain criteria .

PASSWORD GENERATOR Welcome to Password Generator About The App Password Generator is an Open Source project brought to you by Iot Lab,KIIT and it brin

IoT Lab KIIT 3 Oct 21, 2021