1

I am trying to add a themes for users in my Django project. Users can choose between dark mode and light mode.

So in the base.html, I have set the links to be as following:

    <link id="mystylesheet" href="{% static 'css/app-light.css' %}" type="text/css" rel="stylesheet">
        <!-- Mode -->
        <div id="mode" class="section" style="padding-top: 1rem; padding-bottom: 3rem;text-align: right">
            <button onclick="swapStyles('app-light.css')" type="button" class="btn btn-secondary">Light Mode</button>
            <button onclick="swapStyles('app-dark.css')" type="button" class="btn btn-dark">Dark Mode</button>
        </div>
        <!-- Mode -->

I have started a new app called mode with following models.py:

class Setting(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="mode",null=True,blank=True)
    name = models.CharField(max_length=200, null=True)
    value = models.CharField(max_length=200)

    def __str__(self):
        return self.name

here is the javascript

    <script type="text/javascript">

        function getCookie(name) {
            var cookieValue = null;
            if (document.cookie && document.cookie !== '') {
                var cookies = document.cookie.split(';');
                for (var i = 0; i < cookies.length; i++) {
                    var cookie = cookies[i].trim();
                    // Does this cookie string begin with the name we want?
                    if (cookie.substring(0, name.length + 1) === (name + '=')) {
                        cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                        break;
                    }
                }
            }
            return cookieValue;
        }
        var csrftoken = getCookie('csrftoken');

        var cssFile = "{% static 'css' %}"
        function swapStyles(sheet){
            document.getElementById('mystylesheet').href = cssFile + '/' + sheet
            localStorage.setItem('theme', sheet)

            updateTheme(sheet)
        }
        function loadSettings(){
            //Call data and set local storage

            var url = "{% url 'mode:user_settings' %}"
            fetch(url, {
                method:'GET',
                headers:{
                    'Content-type':'application/json'
                }
            })
            .then((response) => response.json())
            .then(function(data){

                console.log('Data:', data)

                var theme = data.value;

                if (theme == 'light.css' || null){
                    swapStyles('light.css')
                }else if(theme == 'dark.css'){
                    swapStyles('dark.css')
                }
            })
        }
        loadSettings()
        function updateTheme(theme){
            var url = "{% url 'mode:update_theme' %}"
            fetch(url, {
                method:'POST',
                headers:{
                    'Content-type':'application/json',
                    'X-CSRFToken':csrftoken,
                },
                body:JSON.stringify({'theme':theme})
            })
        }
    </script>

Here is the urls.py

app_name = 'mode'

urlpatterns = [
    path('user_settings/', views.userSettings, name="user_settings"),
    path('update_theme/', views.updateTheme, name="update_theme"),
]

I have difficulty setting the user settings views.py to reflect when the user is logged in, however, the updated theme is working ok.

def userSettings(request):
    user = request.user
    setting = getattr(user, 'setting', None)

def updateTheme(request):
    data = json.loads(request.body)
    theme = data['theme']

    user = request.user
    setting = Setting.objects.update_or_create(
        user=user, defaults={'value': theme}, name='theme')

    print('Request:', theme)
    return JsonResponse('Updated..', safe=False)

My question: How can I configure the user settings to be set that the user who is currently logged in to have a settings as light mode as a default and if he choose to have it a dark mode to be set in the data base in all the pages and when it is on dark mode and the user choose light mode to be set in the data base.

1
  • I get that you want to set some key value pairs for Users. Why not look into using sessions, its much simpler than creating custom classes to do the same. Commented Jan 14, 2021 at 3:38

1 Answer 1

7

One way you can do this is;

  1. Define a model for user preferences
  2. Create a context processor to pass preferences to your template
  3. Add a check in your template for the users preference, then pass the defined css

You could then force a page refresh on setting change to "apply" the new value.

Here is an example


models.py

class Preferences(models.Model):
    
    themes = (
        ('light', 'Light Theme'),
        ('dark', 'Dark Theme'),
    )
    
    preference_id = models.AutoField(primary_key=True)
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    
    theme = models.CharField(max_length=255, choices=themes)
    
    
    class Meta:
        constraints = [
            models.UniqueConstraint(fields=['user'], name='One Entry Per User')
        ]

context processor

from apps.users.models import Preferences

def pref(request):
    if request.user.is_authenticated:
        _preferences = Preferences.objects.filter(user=request.user).last()
            
    else:
        _preferences = None
            
    return {
        'user_pref': _preferences,
    }

settings.py

TEMPLATES = [
    {
        'BACKEND': ...,
        'DIRS': ...,
        'OPTIONS': {
            'context_processors': [
                'context_processors.user_preferences_context.pref',
                ],
        },
    },
]

base.html

{% if user_pref.theme == 'dark' %}
<link href="{% static 'theme/css/themes/layout/header/base/dark.css' %}" rel="stylesheet" type="text/css" />
<link href="{% static 'theme/css/themes/layout/header/menu/dark.css' %}" rel="stylesheet" type="text/css" />
<link href="{% static 'theme/css/themes/layout/brand/dark.css' %}" rel="stylesheet" type="text/css" />
<link href="{% static 'theme/css/themes/layout/aside/dark.css' %}" rel="stylesheet" type="text/css" />
{% else %}
<link href="{% static 'theme/css/themes/layout/header/base/light.css' %}" rel="stylesheet" type="text/css" />
<link href="{% static 'theme/css/themes/layout/header/menu/light.css' %}" rel="stylesheet" type="text/css" />
<link href="{% static 'theme/css/themes/layout/brand/light.css' %}" rel="stylesheet" type="text/css" />
<link href="{% static 'theme/css/themes/layout/aside/light.css' %}" rel="stylesheet" type="text/css" />
{% endif %}

File structure

project/
    -> apps
        -> Django Apps stored here
    -> context_processors
        -> Custom context processors stored here
    -> project
        -> settings.py
    manage.py
Sign up to request clarification or add additional context in comments.

5 Comments

I followed your steps and I added the context_processors.py in the app folder and in the settings I added it in the context_processors but I am receiving No module named 'context_processors' I also added the name of the to be like this theme.context_processors.user_preferences_context.pref but also got No module named 'theme.context_processors.user_preferences_context'; 'theme.context_processors' is not a package
You need to change the example imports to your environment. I will add my file structure to the question so you can see where everything is.
Added the structure for example. You need to make sure your import points to where your custom context processor sits in your structure.
I managed to add thanks now that the backend is responding to the theme how does the user chooses from the front end I added the buttons
You would need to make a database call when the user modifies the setting. Maybe an ajax or api call to change the setting, then just force a page reload after the value in the db has been updated.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.