mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-11-03 22:55:43 +00:00 
			
		
		
		
	Merge pull request #533 from SchrodingersGat/key-value-settings
Key value settings
This commit is contained in:
		@@ -61,6 +61,7 @@ settings_urls = [
 | 
				
			|||||||
    url(r'^user/?', SettingsView.as_view(template_name='InvenTree/settings/user.html'), name='settings-user'),
 | 
					    url(r'^user/?', SettingsView.as_view(template_name='InvenTree/settings/user.html'), name='settings-user'),
 | 
				
			||||||
    url(r'^currency/?', SettingsView.as_view(template_name='InvenTree/settings/currency.html'), name='settings-currency'),
 | 
					    url(r'^currency/?', SettingsView.as_view(template_name='InvenTree/settings/currency.html'), name='settings-currency'),
 | 
				
			||||||
    url(r'^part/?', SettingsView.as_view(template_name='InvenTree/settings/part.html'), name='settings-part'),
 | 
					    url(r'^part/?', SettingsView.as_view(template_name='InvenTree/settings/part.html'), name='settings-part'),
 | 
				
			||||||
 | 
					    url(r'^other/?', SettingsView.as_view(template_name='InvenTree/settings/other.html'), name='settings-other'),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Catch any other urls
 | 
					    # Catch any other urls
 | 
				
			||||||
    url(r'^.*$', SettingsView.as_view(template_name='InvenTree/settings/user.html'), name='settings'),
 | 
					    url(r'^.*$', SettingsView.as_view(template_name='InvenTree/settings/user.html'), name='settings'),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,6 +16,7 @@ from django.views.generic import UpdateView, CreateView
 | 
				
			|||||||
from django.views.generic.base import TemplateView
 | 
					from django.views.generic.base import TemplateView
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from part.models import Part
 | 
					from part.models import Part
 | 
				
			||||||
 | 
					from common.models import InvenTreeSetting
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .forms import DeleteForm, EditUserForm, SetPasswordForm
 | 
					from .forms import DeleteForm, EditUserForm, SetPasswordForm
 | 
				
			||||||
from .helpers import str2bool
 | 
					from .helpers import str2bool
 | 
				
			||||||
@@ -511,3 +512,11 @@ class SettingsView(TemplateView):
 | 
				
			|||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    template_name = "InvenTree/settings.html"
 | 
					    template_name = "InvenTree/settings.html"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ctx = super().get_context_data(**kwargs).copy()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ctx['settings'] = InvenTreeSetting.objects.all().order_by('key')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return ctx
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,11 +5,17 @@ from django.contrib import admin
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
from import_export.admin import ImportExportModelAdmin
 | 
					from import_export.admin import ImportExportModelAdmin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .models import Currency
 | 
					from .models import Currency, InvenTreeSetting
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CurrencyAdmin(ImportExportModelAdmin):
 | 
					class CurrencyAdmin(ImportExportModelAdmin):
 | 
				
			||||||
    list_display = ('symbol', 'suffix', 'description', 'value', 'base')
 | 
					    list_display = ('symbol', 'suffix', 'description', 'value', 'base')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SettingsAdmin(ImportExportModelAdmin):
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    list_display = ('key', 'value', 'description')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
admin.site.register(Currency, CurrencyAdmin)
 | 
					admin.site.register(Currency, CurrencyAdmin)
 | 
				
			||||||
 | 
					admin.site.register(InvenTreeSetting, SettingsAdmin)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										21
									
								
								InvenTree/common/migrations/0004_inventreesetting.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								InvenTree/common/migrations/0004_inventreesetting.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					# Generated by Django 2.2.5 on 2019-09-15 12:44
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.db import migrations, models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Migration(migrations.Migration):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dependencies = [
 | 
				
			||||||
 | 
					        ('common', '0003_auto_20190902_2310'),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    operations = [
 | 
				
			||||||
 | 
					        migrations.CreateModel(
 | 
				
			||||||
 | 
					            name='InvenTreeSetting',
 | 
				
			||||||
 | 
					            fields=[
 | 
				
			||||||
 | 
					                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
 | 
				
			||||||
 | 
					                ('key', models.CharField(help_text='Settings key', max_length=50, unique=True)),
 | 
				
			||||||
 | 
					                ('value', models.CharField(blank=True, help_text='Settings value', max_length=200)),
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
							
								
								
									
										23
									
								
								InvenTree/common/migrations/0005_auto_20190915_1256.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								InvenTree/common/migrations/0005_auto_20190915_1256.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					# Generated by Django 2.2.5 on 2019-09-15 12:56
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.db import migrations, models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Migration(migrations.Migration):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dependencies = [
 | 
				
			||||||
 | 
					        ('common', '0004_inventreesetting'),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    operations = [
 | 
				
			||||||
 | 
					        migrations.AddField(
 | 
				
			||||||
 | 
					            model_name='inventreesetting',
 | 
				
			||||||
 | 
					            name='description',
 | 
				
			||||||
 | 
					            field=models.CharField(blank=True, help_text='Settings description', max_length=200),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        migrations.AlterField(
 | 
				
			||||||
 | 
					            model_name='inventreesetting',
 | 
				
			||||||
 | 
					            name='key',
 | 
				
			||||||
 | 
					            field=models.CharField(help_text='Settings key (must be unique - case insensitive', max_length=50, unique=True),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
@@ -9,6 +9,79 @@ from __future__ import unicode_literals
 | 
				
			|||||||
from django.db import models
 | 
					from django.db import models
 | 
				
			||||||
from django.utils.translation import ugettext as _
 | 
					from django.utils.translation import ugettext as _
 | 
				
			||||||
from django.core.validators import MinValueValidator, MaxValueValidator
 | 
					from django.core.validators import MinValueValidator, MaxValueValidator
 | 
				
			||||||
 | 
					from django.core.exceptions import ValidationError
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InvenTreeSetting(models.Model):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    An InvenTreeSetting object is a key:value pair used for storing
 | 
				
			||||||
 | 
					    single values (e.g. one-off settings values).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    The class provides a way of retrieving the value for a particular key,
 | 
				
			||||||
 | 
					    even if that key does not exist.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def get_setting(cls, key, backup_value=None):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Get the value of a particular setting.
 | 
				
			||||||
 | 
					        If it does not exist, return the backup value (default = None)
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            setting = InvenTreeSetting.objects.get(key__iexact=key)
 | 
				
			||||||
 | 
					            return setting.value
 | 
				
			||||||
 | 
					        except InvenTreeSetting.DoesNotExist:
 | 
				
			||||||
 | 
					            return backup_value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def set_setting(cls, key, value, user, create=True):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Set the value of a particular setting.
 | 
				
			||||||
 | 
					        If it does not exist, option to create it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Args:
 | 
				
			||||||
 | 
					            key: settings key
 | 
				
			||||||
 | 
					            value: New value
 | 
				
			||||||
 | 
					            user: User object (must be staff member to update a core setting)
 | 
				
			||||||
 | 
					            create: If True, create a new setting if the specified key does not exist.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not user.is_staff:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            setting = InvenTreeSetting.objects.get(key__iexact=key)
 | 
				
			||||||
 | 
					        except InvenTreeSetting.DoesNotExist:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if create:
 | 
				
			||||||
 | 
					                setting = InvenTreeSetting(key=key)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					        setting.value = value
 | 
				
			||||||
 | 
					        setting.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    key = models.CharField(max_length=50, blank=False, unique=True, help_text=_('Settings key (must be unique - case insensitive'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    value = models.CharField(max_length=200, blank=True, unique=False, help_text=_('Settings value'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    description = models.CharField(max_length=200, blank=True, unique=False, help_text=_('Settings description'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def validate_unique(self, exclude=None):
 | 
				
			||||||
 | 
					        """ Ensure that the key:value pair is unique.
 | 
				
			||||||
 | 
					        In addition to the base validators, this ensures that the 'key'
 | 
				
			||||||
 | 
					        is unique, using a case-insensitive comparison.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        super().validate_unique(exclude)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            setting = InvenTreeSetting.objects.exclude(id=self.id).filter(key__iexact=self.key)
 | 
				
			||||||
 | 
					            if setting.exists():
 | 
				
			||||||
 | 
					                raise ValidationError({'key': _('Key string must be unique')})
 | 
				
			||||||
 | 
					        except InvenTreeSetting.DoesNotExist:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Currency(models.Model):
 | 
					class Currency(models.Model):
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										37
									
								
								InvenTree/templates/InvenTree/settings/other.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								InvenTree/templates/InvenTree/settings/other.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					{% extends "InvenTree/settings/settings.html" %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block tabs %}
 | 
				
			||||||
 | 
					{% include "InvenTree/settings/tabs.html" with tab='other' %}
 | 
				
			||||||
 | 
					{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block settings %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<h4>InvenTree Settings</h4>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<table class='table table-striped table-condensed' id='other-table'>
 | 
				
			||||||
 | 
					    <thead>
 | 
				
			||||||
 | 
					        <tr>
 | 
				
			||||||
 | 
					            <th>Setting</th>
 | 
				
			||||||
 | 
					            <th>Value</th>
 | 
				
			||||||
 | 
					            <th>Description</th>
 | 
				
			||||||
 | 
					        </tr>
 | 
				
			||||||
 | 
					    </thead>
 | 
				
			||||||
 | 
					    <tbody>
 | 
				
			||||||
 | 
					        {% for setting in settings %}
 | 
				
			||||||
 | 
					        <tr>
 | 
				
			||||||
 | 
					            <td>{{ setting.key }}</td>
 | 
				
			||||||
 | 
					            <td>{{ setting.value }}</td>
 | 
				
			||||||
 | 
					            <td>{{ setting.description }}</td>
 | 
				
			||||||
 | 
					        </tr>
 | 
				
			||||||
 | 
					        {% endfor %}
 | 
				
			||||||
 | 
					    </tbody>
 | 
				
			||||||
 | 
					</table>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block js_ready %}
 | 
				
			||||||
 | 
					{{ block.super }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $("#other-table").bootstrapTable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% endblock %}
 | 
				
			||||||
@@ -8,4 +8,9 @@
 | 
				
			|||||||
    <li{% ifequal tab 'part' %} class='active'{% endifequal %}>
 | 
					    <li{% ifequal tab 'part' %} class='active'{% endifequal %}>
 | 
				
			||||||
        <a href="{% url 'settings-part' %}"><span class='glyphicon glyphicon-briefcase'></span> Part</a>
 | 
					        <a href="{% url 'settings-part' %}"><span class='glyphicon glyphicon-briefcase'></span> Part</a>
 | 
				
			||||||
    </li>
 | 
					    </li>
 | 
				
			||||||
 | 
					    {% if user.is_staff %}
 | 
				
			||||||
 | 
					    <li{% ifequal tab 'other' %} class='active'{% endifequal %}>
 | 
				
			||||||
 | 
					        <a href="{% url 'settings-other' %}"><span class='glyphicon glyphicon-cog'></span>Other</a>
 | 
				
			||||||
 | 
					    </li>
 | 
				
			||||||
 | 
					    {% endif %}
 | 
				
			||||||
</ul>
 | 
					</ul>
 | 
				
			||||||
		Reference in New Issue
	
	Block a user