Remove constance & use singleton model for dynamc settings

remotes/origin/hasaccess
Ivlev Denis 8 years ago
parent 8c97b56ac2
commit e6b514e71c
  1. 43
      api/v1/serializers/config.py
  2. 19
      api/v1/views.py
  3. 0
      apps/config/__init__.py
  4. 3
      apps/config/admin.py
  5. 5
      apps/config/apps.py
  6. 27
      apps/config/migrations/0001_initial.py
  7. 18
      apps/config/migrations/0002_auto_20180326_1026.py
  8. 23
      apps/config/migrations/0003_auto_20180326_1027.py
  9. 0
      apps/config/migrations/__init__.py
  10. 25
      apps/config/models.py
  11. 3
      apps/config/tests.py
  12. 3
      apps/config/views.py
  13. 5
      apps/content/tasks.py
  14. 4
      apps/payment/models.py
  15. 5
      project/context_processors.py
  16. 14
      project/fields.py
  17. 41
      project/settings.py
  18. 1
      requirements.txt

@ -1,40 +1,25 @@
from constance import config
from constance.admin import get_values, ConstanceForm
from rest_framework import serializers from rest_framework import serializers
from rest_framework.fields import SkipField
from collections import OrderedDict
from apps.config.models import Config
def _set_constance_value(key, value):
form = ConstanceForm(initial=get_values())
field = form.fields[key]
clean_value = field.clean(field.to_python(value))
setattr(config, key, clean_value)
class ConfigSerializer(serializers.ModelSerializer):
class ConfigSerializer(serializers.Serializer):
SERVICE_COMMISSION = serializers.IntegerField(required=False) SERVICE_COMMISSION = serializers.IntegerField(required=False)
SERVICE_DISCOUNT_MIN_AMOUNT = serializers.IntegerField(required=False) SERVICE_DISCOUNT_MIN_AMOUNT = serializers.IntegerField(required=False)
SERVICE_DISCOUNT = serializers.IntegerField(required=False) SERVICE_DISCOUNT = serializers.IntegerField(required=False)
INSTAGRAM_CLIENT_ACCESS_TOKEN = serializers.CharField(required=False) INSTAGRAM_CLIENT_ACCESS_TOKEN = serializers.CharField(required=False)
INSTAGRAM_CLIENT_SECRET = serializers.CharField(required=False) INSTAGRAM_CLIENT_SECRET = serializers.CharField(required=False)
INSTAGRAM_PROFILE_URL = serializers.CharField(required=False) INSTAGRAM_PROFILE_URL = serializers.CharField(required=False)
# SCHOOL_LOGO_IMAGE = serializers.ImageField(required=False) SCHOOL_LOGO_IMAGE = serializers.ImageField(required=False)
def to_representation(self, instance):
ret = OrderedDict()
fields = self._readable_fields
for field in fields:
attribute = instance.get(field.field_name)
ret[field.field_name] = field.to_representation(attribute)
return ret
def to_internal_value(self, data):
ret = OrderedDict(get_values())
for k, v in data.items():
ret[k] = v
return ret
def update(self, instance, validated_data): class Meta:
for k, v in validated_data.items(): model = Config
_set_constance_value(k, v) fields = (
'SERVICE_COMMISSION',
'SERVICE_DISCOUNT_MIN_AMOUNT',
'SERVICE_DISCOUNT',
'INSTAGRAM_CLIENT_ACCESS_TOKEN',
'INSTAGRAM_CLIENT_SECRET',
'INSTAGRAM_PROFILE_URL',
'SCHOOL_LOGO_IMAGE',
)

@ -1,10 +1,6 @@
from constance.admin import get_values
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from rest_framework import status from rest_framework import status, views, viewsets, generics
from rest_framework import views, viewsets
from rest_framework import generics
from rest_framework.decorators import detail_route, list_route from rest_framework.decorators import detail_route, list_route
from rest_framework.response import Response from rest_framework.response import Response
@ -43,6 +39,7 @@ from apps.course.models import (
Material, Lesson, Material, Lesson,
Like, Like,
) )
from apps.config.models import Config
from apps.content.models import ( from apps.content.models import (
Image, Text, ImageText, Video, Image, Text, ImageText, Video,
Gallery, GalleryImage, ImageObject, Gallery, GalleryImage, ImageObject,
@ -327,18 +324,12 @@ class SchoolScheduleViewSet(ExtendedModelViewSet):
class ConfigViewSet(generics.RetrieveUpdateAPIView): class ConfigViewSet(generics.RetrieveUpdateAPIView):
queryset = Config.objects.all()
serializer_class = ConfigSerializer serializer_class = ConfigSerializer
permission_classes = (IsAdmin,) permission_classes = (IsAdmin,)
def retrieve(self, request, *args, **kwargs): def get_object(self):
serializer = ConfigSerializer(get_values()) return Config.load()
return Response(serializer.data)
def patch(self, request, *args, **kwargs):
serializer = ConfigSerializer(data=request.data)
if serializer.is_valid():
serializer.update(get_values(), serializer.validated_data)
return Response(serializer.data)
class CommentViewSet(ExtendedModelViewSet): class CommentViewSet(ExtendedModelViewSet):

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

@ -0,0 +1,5 @@
from django.apps import AppConfig
class ConfigConfig(AppConfig):
name = 'config'

@ -0,0 +1,27 @@
# Generated by Django 2.0.3 on 2018-03-26 10:25
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Config',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('INSTAGRAM_CLIENT_ACCESS_TOKEN', models.CharField(default='7145314808.f6fa114.6b737a5355534e0eb5cf7c40cb4998f6', max_length=51)),
('INSTAGRAM_CLIENT_SECRET', models.CharField(default='2334a921425140ccb180d145dcd35b25', max_length=32)),
('INSTAGRAM_PROFILE_URL', models.CharField(default='#', max_length=126)),
('SERVICE_COMMISSION', models.IntegerField(default=10)),
('SERVICE_DISCOUNT_MIN_AMOUNT', models.IntegerField(default=3500)),
('SERVICE_DISCOUNT', models.ImageField(default=1000, upload_to='')),
('SCHOOL_LOGO_IMAGE', models.ImageField(null=True, upload_to='')),
],
),
]

@ -0,0 +1,18 @@
# Generated by Django 2.0.3 on 2018-03-26 10:26
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('config', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='config',
name='SCHOOL_LOGO_IMAGE',
field=models.FileField(null=True, upload_to=''),
),
]

@ -0,0 +1,23 @@
# Generated by Django 2.0.3 on 2018-03-26 10:27
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('config', '0002_auto_20180326_1026'),
]
operations = [
migrations.AlterField(
model_name='config',
name='SCHOOL_LOGO_IMAGE',
field=models.ImageField(null=True, upload_to=''),
),
migrations.AlterField(
model_name='config',
name='SERVICE_DISCOUNT',
field=models.IntegerField(default=1000),
),
]

@ -0,0 +1,25 @@
from django.db import models
class Config(models.Model):
INSTAGRAM_CLIENT_ACCESS_TOKEN = models.CharField(
max_length=51, default='7145314808.f6fa114.6b737a5355534e0eb5cf7c40cb4998f6'
)
INSTAGRAM_CLIENT_SECRET = models.CharField(max_length=32, default='2334a921425140ccb180d145dcd35b25')
INSTAGRAM_PROFILE_URL = models.CharField(max_length=126, default='#')
SERVICE_COMMISSION = models.IntegerField(default=10)
SERVICE_DISCOUNT_MIN_AMOUNT = models.IntegerField(default=3500)
SERVICE_DISCOUNT = models.IntegerField(default=1000)
SCHOOL_LOGO_IMAGE = models.ImageField(null=True)
def save(self, *args, **kwargs):
self.pk = 1
super().save(*args, **kwargs)
def delete(self, *args, **kwargs):
pass
@classmethod
def load(cls):
obj, created = cls.objects.get_or_create(pk=1)
return obj

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

@ -0,0 +1,3 @@
from django.shortcuts import render
# Create your views here.

@ -3,13 +3,16 @@ import json
import requests import requests
import shutil import shutil
from constance import config
from instagram.client import InstagramAPI from instagram.client import InstagramAPI
from project.celery import app from project.celery import app
from time import sleep from time import sleep
from django.conf import settings from django.conf import settings
from apps.config.models import Config
config = Config.load()
@app.task @app.task
def retrieve_photos(): def retrieve_photos():

@ -1,4 +1,3 @@
from constance import config
from paymentwall import Pingback from paymentwall import Pingback
from polymorphic.models import PolymorphicModel from polymorphic.models import PolymorphicModel
@ -9,9 +8,12 @@ from django.core.validators import RegexValidator
from django.utils.timezone import now from django.utils.timezone import now
from apps.course.models import Course from apps.course.models import Course
from apps.config.models import Config
from apps.school.models import SchoolSchedule from apps.school.models import SchoolSchedule
from apps.notification.utils import send_email from apps.notification.utils import send_email
config = Config.load()
User = get_user_model() User = get_user_model()
CREDIT_CARD_RE = r'^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\d{11})$' CREDIT_CARD_RE = r'^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\d{11})$'

@ -0,0 +1,5 @@
from apps.config.models import Config
def config(request):
return {"config": Config.load()}

@ -0,0 +1,14 @@
from django.forms import ImageField as BaseImageField
class ImageField(BaseImageField):
def to_internal_value(self, data):
# if data is None image field was not uploaded
if data:
file_object = super(ImageField, self).to_internal_value(data)
django_field = self._DjangoImageField()
django_field.error_messages = self.error_messages
django_field.to_python(file_object)
return file_object
return data

@ -17,7 +17,6 @@ from celery.schedules import crontab
from collections import OrderedDict from collections import OrderedDict
from datetime import timedelta from datetime import timedelta
# Build paths inside the project like this: os.path.join(BASE_DIR, ...) # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
@ -53,8 +52,6 @@ INSTALLED_APPS = [
'rest_framework.authtoken', 'rest_framework.authtoken',
'drf_yasg', 'drf_yasg',
'corsheaders', 'corsheaders',
'constance',
'constance.backends.database',
'sorl.thumbnail', 'sorl.thumbnail',
'raven.contrib.django.raven_compat', 'raven.contrib.django.raven_compat',
] + [ ] + [
@ -64,6 +61,7 @@ INSTALLED_APPS = [
'apps.payment', 'apps.payment',
'apps.course', 'apps.course',
'apps.content', 'apps.content',
'apps.config',
'apps.school', 'apps.school',
] ]
@ -90,7 +88,7 @@ TEMPLATES = [
'APP_DIRS': True, 'APP_DIRS': True,
'OPTIONS': { 'OPTIONS': {
'context_processors': [ 'context_processors': [
'constance.context_processors.config', 'project.context_processors.config',
'django.template.context_processors.debug', 'django.template.context_processors.debug',
'django.template.context_processors.request', 'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth', 'django.contrib.auth.context_processors.auth',
@ -204,6 +202,7 @@ REST_FRAMEWORK = {
), ),
'DEFAULT_RENDERER_CLASSES': ( 'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.JSONRenderer', 'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
), ),
'DEFAULT_FILTER_BACKENDS': ( 'DEFAULT_FILTER_BACKENDS': (
'django_filters.rest_framework.DjangoFilterBackend', 'django_filters.rest_framework.DjangoFilterBackend',
@ -228,40 +227,6 @@ CELERY_BEAT_SCHEDULE = {
}, },
} }
# Dynamic settings
CONSTANCE_BACKEND = 'constance.backends.database.DatabaseBackend'
CONSTANCE_ADDITIONAL_FIELDS = {
'image_field': ['django.forms.ImageField', {}]
}
CONSTANCE_CONFIG = OrderedDict((
('INSTAGRAM_CLIENT_ACCESS_TOKEN', ('7145314808.f6fa114.6b737a5355534e0eb5cf7c40cb4998f6', '')),
('INSTAGRAM_CLIENT_SECRET', ('2334a921425140ccb180d145dcd35b25', '')),
('INSTAGRAM_PROFILE_URL', ('#', 'URL профиля Instagram.')),
('INSTAGRAM_RESULTS_TAG', ('#lil_акварель', 'Тэг результатов работ.')),
('INSTAGRAM_RESULTS_PATH', ('media/instagram/results/', 'Путь до результатов работ.')),
('SERVICE_COMMISSION', (10, 'Комиссия сервиса в процентах.')),
('SERVICE_DISCOUNT_MIN_AMOUNT', (3500, 'Минимальная сумма платежа для школы, после которой вычитывается скидка SERVICE_DISCOUNT.')),
('SERVICE_DISCOUNT', (1000, 'Комиссия сервиса при покупке всех дней.')),
# ('SCHOOL_LOGO_IMAGE', ('default.png', 'Изображение в диалоге покупки школы', 'image_field')),
))
CONSTANCE_CONFIG_FIELDSETS = OrderedDict({
'Service': (
'SERVICE_COMMISSION',
'SERVICE_DISCOUNT_MIN_AMOUNT',
'SERVICE_DISCOUNT',
# 'SCHOOL_LOGO_IMAGE',
),
'Instagram': (
'INSTAGRAM_CLIENT_ACCESS_TOKEN',
'INSTAGRAM_CLIENT_SECRET',
'INSTAGRAM_PROFILE_URL',
'INSTAGRAM_RESULTS_TAG',
'INSTAGRAM_RESULTS_PATH',
),
})
try: try:
from paymentwall import * from paymentwall import *
except ImportError: except ImportError:

@ -5,7 +5,6 @@ Django==2.0.3
django-active-link==0.1.2 django-active-link==0.1.2
django-anymail[mailgun]==2.0 django-anymail[mailgun]==2.0
django-cors-headers==2.2.0 django-cors-headers==2.2.0
django-constance[database]==2.1.0
django-filter==2.0.0.dev1 django-filter==2.0.0.dev1
django-mptt==0.9.0 django-mptt==0.9.0
django-silk==2.0.0 django-silk==2.0.0

Loading…
Cancel
Save