Source code for shuup.admin.modules.settings.view_settings

# This file is part of Shuup.
#
# Copyright (c) 2012-2021, Shuup Commerce Inc. All rights reserved.
#
# This source code is licensed under the OSL-3.0 license found in the
# LICENSE file in the root directory of this source tree.
import django
import six
from django.apps import apps
from django.conf import settings
from django.db.models import BooleanField, CharField, ForeignKey
from enumfields import EnumIntegerField

from shuup import configuration
from shuup.admin.utils.picotable import ChoicesFilter, Column, TextFilter, true_or_false_filter
from shuup.apps.provides import get_provide_objects
from shuup.utils.importing import load

INVALID_FIELDS = ["ptr", "ctype", "key", "label" "master"]


[docs]class ViewSettings(object): key = "view_configuration_%s_%s" column_spec = [] def __init__(self, model, default_columns, view_context, *args, **kwargs): if isinstance(model, six.string_types) and model == settings.AUTH_USER_MODEL: model = apps.get_model(settings.AUTH_USER_MODEL) self.model = model self.default_columns = default_columns self.view_context = view_context self.ensure_initial_columns(default_columns) self.column_spec = self._build_settings_columns() self.active_columns = [] self.inactive_columns = [] self._create_columns() def _create_columns(self): for column in self.column_spec: config = self.get_config(column.id) try: # backwards compatibility int(config) old_mode = True except Exception: old_mode = False column.ordering = config.get("ordering", 9999) if not old_mode else 9999 if old_mode: # old and active if config > 1: self.active_columns.append(column) else: self.inactive_columns.append(column) else: if config.get("active", False): self.active_columns.append(column) else: self.inactive_columns.append(column) self.active_columns.sort(key=lambda x: x.ordering) self.inactive_columns.sort(key=lambda x: x.title) self.columns = self.active_columns
[docs] def ensure_initial_columns(self, default_columns): if not self.view_configured(): # generate the default stuff for default_column in default_columns: self.set_config(default_column.id, {"ordering": default_column.ordering, "active": True}) self.set_config("saved", True)
[docs] def get_config(self, value): val = configuration.get(None, self.get_settings_key(value), {}) return val
[docs] def set_config(self, key_value, value, use_key=False): key = self.get_settings_key(key_value) if not use_key else key_value return configuration.set(None, key, value)
[docs] def get_settings_key(self, value): return self.key % (self.model.__name__.lower(), value)
[docs] def view_configured(self): return self.get_config("saved")
def _valid_field(self, field_identifier): return not len([field for field in INVALID_FIELDS if field in field_identifier]) def _build_settings_columns(self): columns = [] all_models = [(None, self.model)] defaults = [col.id for col in self.default_columns] known_names = [] for identifier, m in self.view_context.related_objects: all_models.append((identifier, load(m))) for identifier, model in all_models: if hasattr(model, "_parler_meta"): self._add_translated_columns(columns, defaults, identifier, known_names, model) self._add_local_columns(all_models, columns, defaults, identifier, known_names, model) self._add_m2m_columns(all_models, columns, defaults, identifier, known_names, model) self._add_provided_columns(columns, identifier, known_names, model) table_columns = set([col.id for col in columns]) for default_column in self.default_columns: if default_column.id not in table_columns and default_column.id != "select": columns.append(default_column) return columns def _add_m2m_columns(self, all_models, columns, defaults, identifier, known_names, model): models_from_all_models = [model for identifier, model in all_models] for field in model._meta.local_many_to_many: if field.name in defaults: continue if django.VERSION < (1, 9): to = field.rel.to else: to = field.remote_field.target_field if to in models_from_all_models: continue # no need to have these... column = self._get_column(model, field, known_names, identifier) if column: columns.append(column) def _add_local_columns(self, all_models, columns, defaults, identifier, known_names, model): models_from_all_models = [model for identifier, model in all_models] for field in model._meta.local_fields: if field.name in defaults: continue if field.name == "id" and model != self.model: continue if django.VERSION < (1, 9): if isinstance(field, ForeignKey) and field.rel.to in models_from_all_models: continue # no need to have these... else: if isinstance(field, ForeignKey) and field.remote_field.target_field in models_from_all_models: continue # no need to have these... column = self._get_column(model, field, known_names, identifier) if column: columns.append(column) def _add_translated_columns(self, columns, defaults, identifier, known_names, model): for field in model._parler_meta.root_model._meta.get_fields(): if field.name in defaults: continue if field.name in ["id", "master", "language_code"]: # exclude these fields continue column = self._get_translated_column(model, field, known_names, identifier) columns.append(column) def _get_translated_column(self, model, field, known_names, identifier): field_name = field.verbose_name.title() if identifier: field_name = "%s %s" % (identifier.replace("_", " ").capitalize(), field_name) # take the first extension, usually we should not have more then one translation_rel_name = model._parler_meta._extensions[0].rel_name if model != self.model: filter_field = "%s__%s__%s" % (identifier, translation_rel_name, field.name) if identifier else field.name else: filter_field = "%s__%s" % (translation_rel_name, field.name) display = "%s__%s" % (identifier, field.name) if identifier else field.name column = Column( "%s_%s" % ((identifier if identifier else model.__name__.lower()), field.name), field_name, sort_field=display, display=display, filter_config=TextFilter(filter_field=filter_field, placeholder=field_name), ) return self.handle_special_column(field, column)[0]
[docs] def handle_special_column(self, field, column): is_special = False for original_column in self.default_columns: if original_column.id == column.id: column.__dict__ = original_column.__dict__.copy() # shallow copy is_special = True return (column, is_special)
def _get_column(self, model, field, known_names, identifier): if not self._valid_field(field.name): return None field_name = field.verbose_name.title() if identifier: field_name = "%s %s" % (identifier.replace("_", " ").capitalize(), field_name) display = "%s__%s" % (identifier, field.name) if identifier else field.name column = Column( "%s_%s" % ((identifier if identifier else model.__name__.lower()), field.name), field_name, display=display ) column, is_special = self.handle_special_column(field, column) if not is_special: if isinstance(field, CharField): column.filter_config = TextFilter(filter_field=field.name, placeholder=field_name) if isinstance(field, EnumIntegerField): column.filter_config = ChoicesFilter(field.choices) if isinstance(field, BooleanField): column.filter_config = true_or_false_filter return column def _add_provided_columns(self, columns, identifier, known_names, model): provide_object_key = "provided_columns_%s" % model.__name__ for provided_column_object in get_provide_objects(provide_object_key): obj = provided_column_object() column = obj.get_column(model, known_names, identifier) if column: columns.append(column)