diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 11614af2870733183efe883810764d8708bddf8f..0000000000000000000000000000000000000000 --- a/.gitignore +++ /dev/null @@ -1,115 +0,0 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -share/python-wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -.hypothesis/ -.pytest_cache/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py -db.sqlite3 - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -.python-version - -# celery beat schedule file -celerybeat-schedule - -# SageMath parsed files -*.sage.py - -# Environments -.env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ diff --git a/README.en.md b/README.en.md deleted file mode 100644 index 4b7fca0166d8a9f0c616c9b2a9c2602eb306c384..0000000000000000000000000000000000000000 --- a/README.en.md +++ /dev/null @@ -1,36 +0,0 @@ -# django-kelove-setting - -#### Description -快速定制django配置,统一管理配置信息 - -#### Software Architecture -Software architecture description - -#### Installation - -1. xxxx -2. xxxx -3. xxxx - -#### Instructions - -1. xxxx -2. xxxx -3. xxxx - -#### Contribution - -1. Fork the repository -2. Create Feat_xxx branch -3. Commit your code -4. Create Pull Request - - -#### Gitee Feature - -1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md -2. Gitee blog [blog.gitee.com](https://blog.gitee.com) -3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) -4. The most valuable open source project [GVP](https://gitee.com/gvp) -5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) -6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/django_kelove_setting/__init__.py b/django_kelove_setting/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..2fdc3540f7401f3398f4bcd382122969275ff724 --- /dev/null +++ b/django_kelove_setting/__init__.py @@ -0,0 +1,7 @@ +""" +__init__.py +By IT小强xqitw.cn +At 1/24/21 11:10 AM +""" + +default_app_config = "django_kelove_setting.apps.DjangoKeloveSettingConfig" diff --git a/django_kelove_setting/admin.py b/django_kelove_setting/admin.py new file mode 100644 index 0000000000000000000000000000000000000000..c93663b0e505e693e52a1bbda82c59385ef896db --- /dev/null +++ b/django_kelove_setting/admin.py @@ -0,0 +1,167 @@ +""" +admin.py +By IT小强xqitw.cn +At 1/24/21 11:29 AM +""" + +from collections import Iterable +from importlib import import_module + +from django.contrib.admin import ModelAdmin, site +from django.http import HttpResponseRedirect +from django.urls import reverse +from django.apps import apps + +from .models import Settings as SettingsModel +from .setting_forms import Settings as SettingsForm + + +def load_object(path: str): + """ + Load an object given its absolute object path, and return it. + object can be a class, function, variable or an instance. + path ie: 'scrapy.downloadermiddlewares.redirect.RedirectMiddleware' + """ + + dot = path.rindex('.') + module, name = path[:dot], path[dot + 1:] + mod = import_module(module) + return getattr(mod, name) + + +class SettingsModelAdmin(ModelAdmin): + """ + 配置管理 + """ + + change_form_template = 'kelove_setting/change_form.html' + + list_display = ( + 'id', + 'settings_title', + 'settings_key', + 'created_user', + 'created_time', + 'updated_user', + 'updated_time', + ) + + list_display_links = ('settings_title', 'settings_key') + + list_filter = ('created_time', 'updated_time') + + search_fields = ('settings_title', 'settings_key') + + readonly_fields = ('settings_title', 'settings_key') + + def get_fieldsets(self, request, obj=None): + """ + Hook for specifying fieldsets. + :param request: + :param obj: + :return: + """ + form = self.get_form(request=request, obj=obj) + if form.fieldsets: + return form.fieldsets + fieldsets = form.get_fieldsets(model_admin=self, request=request, obj=obj) + if fieldsets: + return fieldsets + return super().get_fieldsets(request=request, obj=obj) + + def has_change_permission(self, request, obj=None): + if not obj: + return super().has_change_permission(request, obj) + return request.user.has_perm(obj.get_settings_permission_code('change')) + + def has_delete_permission(self, request, obj=None): + if not obj: + return super().has_delete_permission(request, obj) + return request.user.has_perm(obj.get_settings_permission_code('delete')) + + def has_view_permission(self, request, obj=None): + if not obj: + return super().has_view_permission(request, obj) + return ( + request.user.has_perm(obj.get_settings_permission_code('change')) or + request.user.has_perm(obj.get_settings_permission_code('view')) + ) + + def add_view(self, request, form_url='', extra_context=None): + """ + 初始化 + :param request: + :param form_url: + :param extra_context: + :return: + """ + kelove_settings_app_key = 'kelove_settings' + app_configs = apps.get_app_configs() + kelove_settings = [ + j + for i in app_configs + for j in getattr(i, kelove_settings_app_key, []) + if + hasattr(i, kelove_settings_app_key) + and isinstance(getattr(i, kelove_settings_app_key, []), Iterable) + and not isinstance(getattr(i, kelove_settings_app_key, []), str) + ] + + for form in kelove_settings: + if isinstance(form, str): + try: + form = load_object(form) + except ModuleNotFoundError: + continue + + if not issubclass(form, SettingsForm): + continue + + obj, is_create = SettingsModel.objects.get_or_create( + settings_key=form.get_settings_key(), + settings_title=form.get_settings_title(is_full=False), + settings_val=form.get(), + created_user=request.user, + updated_user=request.user + ) + obj.create_admin_settings_auth() + form.delete_cache() + + opts = self.model._meta + obj_url = reverse( + 'admin:%s_%s_changelist' % (opts.app_label, opts.model_name), + current_app=self.admin_site.name, + ) + return HttpResponseRedirect(obj_url) + + def get_form(self, request, obj=None, change=False, **kwargs): + if obj: + try: + form = load_object(obj.settings_key) + if issubclass(form, SettingsForm): + return form + except AttributeError: + pass + return super().get_form(request, obj, change, **kwargs) + + def save_model(self, request, obj, form, change): + """ + Given a model instance save it to the database. + 自动写入创建用户ID和更新用户ID + :param request: + :param obj: + :param form: + :param change: + :return: + """ + + if request.user: + user = request.user + obj.updated_user = user + if not change: + obj.created_user = user + super().save_model(request, obj, form, change) + + +if not site.is_registered(SettingsModel): + site.register(SettingsModel, SettingsModelAdmin) diff --git a/django_kelove_setting/apps.py b/django_kelove_setting/apps.py new file mode 100644 index 0000000000000000000000000000000000000000..e7acf1e4dae5c54be5d25da8dfbeefb5b7fdb11a --- /dev/null +++ b/django_kelove_setting/apps.py @@ -0,0 +1,22 @@ +""" +apps.py +By IT小强xqitw.cn +At 1/24/21 11:11 AM +""" + +from django.apps import AppConfig +from django.utils.translation import gettext_lazy as _ + + +class DjangoKeloveSettingConfig(AppConfig): + """ + DjangoKeloveSettingConfig + """ + + label = 'django_kelove_setting' + name = 'django_kelove_setting' + verbose_name = _('应用配置') + + kelove_settings = [ + 'django_kelove_setting.kelove_settings.EmailSettings' + ] diff --git a/django_kelove_setting/kelove_settings.py b/django_kelove_setting/kelove_settings.py new file mode 100644 index 0000000000000000000000000000000000000000..752d40974bc535d441f608c13b1760d5c2649c73 --- /dev/null +++ b/django_kelove_setting/kelove_settings.py @@ -0,0 +1,113 @@ +""" +kelove_settings.py +By IT小强xqitw.cn +At 1/24/21 11:47 AM +""" + +from django.utils.translation import gettext_lazy as _ +from django.conf import settings +from django import forms + +from .setting_forms import Settings + + +class EmailSettings(Settings): + """ + 邮件配置 + """ + + settings_title: str = _('邮件配置') + + fieldsets = ( + (_('基础配置'), { + 'fields': ( + 'EMAIL_HOST', + 'EMAIL_PORT', + 'EMAIL_HOST_USER', + 'DEFAULT_FROM_EMAIL', + 'OTP_EMAIL_SENDER', + 'EMAIL_HOST_PASSWORD', + ), + 'classes': ('extrapretty', 'wide') + }), + (_('安全链接'), { + 'fields': ( + 'EMAIL_USE_TLS', + 'EMAIL_USE_SSL', + ), + 'classes': ('extrapretty', 'wide') + }), + (_('配置信息'), { + 'fields': ( + 'settings_title', + 'settings_key', + ), + 'classes': ('extrapretty', 'wide') + }) + ) + + EMAIL_HOST = forms.CharField( + initial=getattr(settings, 'EMAIL_HOST', 'smtp.qq.com'), + empty_value=getattr(settings, 'EMAIL_HOST', 'smtp.qq.com'), + required=False, + label=_('邮件服务器域名'), + help_text=_('例如:smtp.qq.com') + ) + + EMAIL_PORT = forms.IntegerField( + initial=getattr(settings, 'EMAIL_PORT', 465), + required=False, + label=_('邮件服务器端口号,为数字'), + help_text=_('例如:465') + ) + + EMAIL_HOST_USER = forms.CharField( + initial=getattr(settings, 'EMAIL_HOST_USER', ''), + required=False, + label=_('发件人邮箱'), + ) + + DEFAULT_FROM_EMAIL = forms.CharField( + initial=getattr(settings, 'DEFAULT_FROM_EMAIL', ''), + required=False, + label=_('发件人地址'), + help_text=_('fred@example.com 和 Fred <fred@example.com> 形式都是合法的') + ) + + OTP_EMAIL_SENDER = forms.CharField( + initial=getattr(settings, 'OTP_EMAIL_SENDER', ''), + required=False, + label=_('一次性验证码发件人地址'), + help_text=_('留空自动使用发件人地址。fred@example.com 和 Fred <fred@example.com> 形式都是合法的') + ) + + EMAIL_HOST_PASSWORD = forms.CharField( + widget=forms.PasswordInput(render_value=True), + initial=getattr(settings, 'EMAIL_HOST_PASSWORD', ''), + required=False, + label=_('发件人授权码'), + help_text=_('发件人授权码不一定是邮箱密码') + ) + + EMAIL_USE_TLS = forms.BooleanField( + initial=getattr(settings, 'EMAIL_USE_TLS', False), + required=False, + label=_('是否启用安全链接TLS'), + help_text=_('通常端口为587 TLS/SSL是相互排斥的,因此仅将其中一个设置设置为启用即可') + ) + + EMAIL_USE_SSL = forms.BooleanField( + initial=getattr(settings, 'EMAIL_USE_SSL', True), + required=False, + label=_('是否启用安全链接SSL'), + help_text=_('通常端口为465 TLS/SSL是相互排斥的,因此仅将其中一个设置设置为启用即可') + ) + + @classmethod + def get(cls) -> dict: + data = super().get() + otp_email_sender_value = data.get('OTP_EMAIL_SENDER', '') + if not otp_email_sender_value: + otp_email_sender_value = data.get('DEFAULT_FROM_EMAIL', '') + data['OTP_EMAIL_SENDER'] = otp_email_sender_value + return data diff --git a/django_kelove_setting/migrations/0001_initial.py b/django_kelove_setting/migrations/0001_initial.py new file mode 100644 index 0000000000000000000000000000000000000000..de2a5c0569478a7597dae08b8cfd45d31e84a595 --- /dev/null +++ b/django_kelove_setting/migrations/0001_initial.py @@ -0,0 +1,34 @@ +# Generated by Django 3.1.5 on 2021-01-24 03:25 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Settings', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('settings_key', models.CharField(db_index=True, max_length=191, unique=True, verbose_name='配置标识')), + ('settings_title', models.CharField(blank=True, default='', max_length=191, verbose_name='配置名称')), + ('settings_val', models.JSONField(blank=True, default=dict, verbose_name='配置内容')), + ('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), + ('updated_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')), + ('created_user', models.ForeignKey(blank=True, db_constraint=False, default=None, editable=False, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='django_kelove_setting_settings_created_user_set', to=settings.AUTH_USER_MODEL, verbose_name='创建用户')), + ('updated_user', models.ForeignKey(blank=True, db_constraint=False, default=None, editable=False, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='django_kelove_setting_settings_updated_user_set', to=settings.AUTH_USER_MODEL, verbose_name='更新用户')), + ], + options={ + 'verbose_name': '应用配置', + 'verbose_name_plural': '应用配置', + }, + ), + ] diff --git a/django_kelove_setting/migrations/__init__.py b/django_kelove_setting/migrations/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..c3893fb8b481942338f9eb4b967bbba055ea0693 --- /dev/null +++ b/django_kelove_setting/migrations/__init__.py @@ -0,0 +1,5 @@ +""" +__init__.py +By IT小强xqitw.cn +At 1/24/21 11:20 AM +""" diff --git a/django_kelove_setting/models.py b/django_kelove_setting/models.py new file mode 100644 index 0000000000000000000000000000000000000000..dc36f4c79bf8a802affbfc40e9141b88dcfe3125 --- /dev/null +++ b/django_kelove_setting/models.py @@ -0,0 +1,124 @@ +""" +models.py +By IT小强xqitw.cn +At 1/24/21 11:16 AM +""" +from django.conf import settings +from django.contrib.auth.models import Permission +from django.db import models +from django.contrib.auth import get_permission_codename +from django.contrib.admin.options import get_content_type_for_model +from django.utils.translation import gettext_lazy as _ + + +class Settings(models.Model): + """ + 配置表 + """ + + settings_key = models.CharField( + verbose_name=_('配置标识'), + unique=True, + db_index=True, + max_length=191, + blank=False, + null=False + ) + + settings_title = models.CharField( + verbose_name=_('配置名称'), + max_length=191, + default='', + blank=True, + null=False + ) + + settings_val = models.JSONField( + verbose_name=_('配置内容'), + default=dict, + null=False, + blank=True + ) + + # 创建用户 + created_user = models.ForeignKey( + settings.AUTH_USER_MODEL, + verbose_name=_('创建用户'), + related_name="%(app_label)s_%(class)s_created_user_set", + on_delete=models.SET_NULL, + db_constraint=False, + null=True, + blank=True, + editable=False, + default=None + ) + + # 更新用户 + updated_user = models.ForeignKey( + settings.AUTH_USER_MODEL, + verbose_name=_('更新用户'), + related_name="%(app_label)s_%(class)s_updated_user_set", + on_delete=models.SET_NULL, + db_constraint=False, + null=True, + blank=True, + editable=False, + default=None + ) + + # 创建时间 + created_time = models.DateTimeField(verbose_name=_('创建时间'), auto_now_add=True, editable=True) + + # 更新时间 + updated_time = models.DateTimeField(verbose_name=_('更新时间'), auto_now=True) + + def get_settings_permission_codename(self, action): + """ + 获取配置权限代码 + :param action: + :return: + """ + + return get_permission_codename(action, self._meta) + '_{key}'.format(key=self.settings_key) + + def get_settings_permission_code(self, action): + """ + 获取配置权限代码(包括app label) + :param action: + :return: + """ + + return "%s.%s" % (self._meta.app_label, self.get_settings_permission_codename(action)) + + def create_admin_settings_auth(self): + """ + 初始化配置权限 + :return: + """ + + content_type = get_content_type_for_model(self) + + Permission.objects.get_or_create( + codename=self.get_settings_permission_codename('change'), + name='Can change {value}'.format(value=self.settings_title), + content_type=content_type, + ) + + Permission.objects.get_or_create( + codename=self.get_settings_permission_codename('delete'), + name='Can delete {value}'.format(value=self.settings_title), + content_type=content_type, + ) + + Permission.objects.get_or_create( + codename=self.get_settings_permission_codename('view'), + name='Can view {value}'.format(value=self.settings_title), + content_type=content_type, + ) + + def __str__(self): + return '%s | %s' % (self.settings_title, self.settings_key) + + class Meta: + verbose_name = _('应用配置') + verbose_name_plural = _('应用配置') diff --git a/django_kelove_setting/setting_forms.py b/django_kelove_setting/setting_forms.py new file mode 100644 index 0000000000000000000000000000000000000000..7c0944f934783b8cf861c6bc9f50e4963adc31d3 --- /dev/null +++ b/django_kelove_setting/setting_forms.py @@ -0,0 +1,252 @@ +""" +settings.py +By IT小强xqitw.cn +At 1/24/21 11:44 AM +""" + +import json +from hashlib import md5 + +from django.db import ProgrammingError, OperationalError +from django.forms.models import ModelForm, model_to_dict +from django.forms.fields import CharField +from django.forms.widgets import HiddenInput +from django.conf import settings +from django.core.cache import cache +from django.utils.translation import gettext_lazy as _ + +from .models import Settings as SettingsModel + + +class Settings(ModelForm): + """ + 配置表单基类 + """ + + settings_title: str = _('未命名') + + settings_val = CharField(widget=HiddenInput(), required=False) + + fieldsets = () + + def __init__(self, data=None, files=None, **kwargs): + initial = kwargs.get('initial', {}) + instance = kwargs.get('instance', None) + kwargs['initial'] = { + **initial, + **self.init_form_initial(instance=instance) + } + super().__init__(data=data, files=files, **kwargs) + + def clean(self): + settings_val = self.get() + for key, val in self.cleaned_data.items(): + if key != 'settings_val' and key in self.changed_data: + settings_val[key] = val + + self.cleaned_data['settings_val'] = settings_val + return super().clean() + + def init_form_data(self, data=None, instance=None): + """ + 初始化表单数据 + :param data: + :param instance: + :return: + """ + + # 表单数据已存在时,不做处理 + if data is not None: + return data + return self.init_form_initial(instance=instance) + + def init_form_initial(self, instance=None): + """ + 初始化表单初始值 + :param instance: + :return: + """ + + data = {} + + if not instance: + return data + + # 查询结果转为字典 + instance_data = model_to_dict(instance) + + # 循环处理配置值 + settings_val = instance_data.get('settings_val', {}) + if not settings_val: + settings_val = {} + if isinstance(settings_val, str): + try: + settings_val = json.loads(settings_val) + except json.JSONDecodeError: + settings_val = {} + + for field_name, field_info in self.base_fields.items(): + if field_name == 'settings_val': + continue + try: + data[field_name] = settings_val.get(field_name, self.get_initial(field_info)) + except AttributeError: + pass + + data['settings_key'] = instance_data['settings_key'] + data['settings_title'] = instance_data['settings_title'] + return data + + @classmethod + def get_settings_key(cls): + """ + 获取当前配置类标识 + :return: + """ + + return '{module}.{name}'.format( + module=cls.__module__, + name=cls.__name__ + ) + + @classmethod + def get_settings_title(cls, is_full=True): + """ + 获取当前配置类名称 + :param is_full: + :return: + """ + + if not is_full: + return cls.settings_title + return '{base_name}【{module}.{name}】'.format( + base_name=cls.settings_title, + module=cls.__module__, + name=cls.__name__ + ) + + @classmethod + def get_cache_key(cls): + """ + 获取缓存标识 + :return: + """ + + return 'settings_{file}_{key}_cache'.format( + file=md5(__file__.encode()).hexdigest(), + key=md5(cls.get_settings_key().encode()).hexdigest() + ) + + @classmethod + def delete_cache(cls): + """ + 删除缓存 + :return: + """ + + cache_key = cls.get_cache_key() + cache.delete(cache_key) + + @classmethod + def get(cls) -> dict: + """ + 获取配置 + :return: + """ + + cache_key = cls.get_cache_key() + cache_data = cache.get(cache_key) + if cache_data is None: + try: + data = SettingsModel.objects.get(settings_key=cls.get_settings_key()) + data = data.settings_val + except (SettingsModel.DoesNotExist, ProgrammingError, OperationalError): + data = {} + initial_data = {} + for key, val in cls.base_fields.items(): + if key == 'settings_val': + continue + try: + initial_data[key] = cls.get_initial(val) + except AttributeError: + pass + cache_data = {**initial_data, **data} + cache.set(cache_key, cache_data) + + return cache_data + + @classmethod + def get_item(cls, key: str, default=None): + """ + 获取单个配置 + :param key: + :param default: + :return: + """ + + return cls.get().get(key, default) + + @classmethod + def get_initial(cls, field): + """ + 获取初始值 + :param field: + :return: + """ + + value = getattr(field, 'initial') + if callable(value): + value = value() + return value + + @classmethod + def get_initial_with_default(cls, field, default): + """ + 获取初始值,不存在时返回 default + :param field: + :param default: + :return: + """ + + value = getattr(field, 'initial', default) + if callable(value): + value = value() + return value + + @classmethod + def change_django_settings(cls): + """ + 刷新django设置 + :return: + """ + + for key, val in cls.get().items(): + setattr(settings, key, val) + + def update_choices(self, field, value): + """ + 动态更新可选项 + :param field: + :param value: + :return: + """ + self.fields[field].choices = value + self.fields[field].widget.choices = value + self.base_fields[field].choices = value + self.base_fields[field].widget.choices = value + + def save(self, commit=True): + self.delete_cache() + return super().save(commit) + + @classmethod + def get_fieldsets(cls, model_admin, request, obj=None): + return cls.fieldsets + + class Meta: + """ + Meta + """ + + model = SettingsModel + fields = ['settings_val'] diff --git a/django_kelove_setting/templates/kelove_setting/change_form.html b/django_kelove_setting/templates/kelove_setting/change_form.html new file mode 100644 index 0000000000000000000000000000000000000000..7755704cc050cc0d898701f92528031eb80d9469 --- /dev/null +++ b/django_kelove_setting/templates/kelove_setting/change_form.html @@ -0,0 +1,6 @@ +{% extends 'admin/change_form.html' %} + +{% block extrastyle %} + {{ block.super }} + {% include 'kelove_setting/form_css.html' %} +{% endblock %} \ No newline at end of file diff --git a/django_kelove_setting/templates/kelove_setting/form_css.html b/django_kelove_setting/templates/kelove_setting/form_css.html new file mode 100644 index 0000000000000000000000000000000000000000..18ccc9cb42b3a27c78e25eec2dc98d7b6db2da06 --- /dev/null +++ b/django_kelove_setting/templates/kelove_setting/form_css.html @@ -0,0 +1,49 @@ + \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000000000000000000000000000000000000..f56a46e794bf967624364bb23b552316fec92336 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,57 @@ +[tool.poetry] +name = "django-kelove-setting" + +version = "0.1.0" + +description = "DJANGO 配置管理" + +license = "Apache-2.0" + +authors = ["IT小强xqitw.cn "] + +maintainers = ["IT小强xqitw.cn "] + +readme = "README.md" + +homepage = "https://gitee.com/itxq/django-kelove-setting" + +repository = "https://gitee.com/itxq/django-kelove-setting.git" + +documentation = "https://gitee.com/itxq/django-kelove-setting/blob/master/README.md" + +keywords = [ + 'django', + 'django-kelove', + 'django-kelove-setting', +] + +classifiers = [ + 'Development Status :: 3 - Alpha', + 'Intended Audience :: Developers', + "Natural Language :: Chinese (Simplified)", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Framework :: Django :: 3.1", +] + +packages = [ + { include = "django_kelove_setting" }, +] + +[tool.poetry.dependencies] +python = "^3.6" +django = "^3.1" + +[tool.poetry.dev-dependencies] + +[[tool.poetry.source]] +name = "tencent" +default = true +url = "https://mirrors.cloud.tencent.com/pypi/simple/" + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api"