Init Django-SHOP
This commit is contained in:
0
weirdlittleempire/management/__init__.py
Normal file
0
weirdlittleempire/management/__init__.py
Normal file
0
weirdlittleempire/management/commands/__init__.py
Normal file
0
weirdlittleempire/management/commands/__init__.py
Normal file
37
weirdlittleempire/management/commands/assign_iconfonts.py
Normal file
37
weirdlittleempire/management/commands/assign_iconfonts.py
Normal file
@@ -0,0 +1,37 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from cmsplugin_cascade.icon.utils import zipfile, unzip_archive
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Iterates over all files in Filer and creates an IconFont for all eligibles."
|
||||
|
||||
def handle(self, verbosity, *args, **options):
|
||||
self.verbosity = verbosity
|
||||
self.assign_files_to_iconfonts()
|
||||
|
||||
def assign_files_to_iconfonts(self):
|
||||
from filer.models.filemodels import File
|
||||
from cmsplugin_cascade.models import IconFont
|
||||
|
||||
for file in File.objects.all():
|
||||
if file.label != 'Font Awesome':
|
||||
continue
|
||||
if self.verbosity >= 2:
|
||||
self.stdout.write(
|
||||
"Creating Icon Font from: {}".format(file.label))
|
||||
try:
|
||||
zip_ref = zipfile.ZipFile(file.file, 'r')
|
||||
except zipfile.BadZipFile as exc:
|
||||
self.stderr.write(
|
||||
"Unable to unpack {}: {}".format(file.label, exc))
|
||||
else:
|
||||
if not IconFont.objects.filter(zip_file=file).exists():
|
||||
font_folder, config_data = unzip_archive(
|
||||
file.label, zip_ref)
|
||||
IconFont.objects.create(
|
||||
identifier=config_data['name'],
|
||||
config_data=config_data,
|
||||
zip_file=file,
|
||||
font_folder=font_folder,
|
||||
)
|
||||
zip_ref.close()
|
||||
41
weirdlittleempire/management/commands/create_social_icons.py
Normal file
41
weirdlittleempire/management/commands/create_social_icons.py
Normal file
@@ -0,0 +1,41 @@
|
||||
from cms.models.static_placeholder import StaticPlaceholder
|
||||
from django.core.management.base import BaseCommand
|
||||
from cmsplugin_cascade.models import CascadeClipboard
|
||||
from shop.management.utils import deserialize_to_placeholder
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Iterates over all files in Filer and creates an IconFont for all eligibles."
|
||||
|
||||
def handle(self, verbosity, *args, **options):
|
||||
self.verbosity = verbosity
|
||||
self.create_social_icons()
|
||||
|
||||
def create_social_icons(self):
|
||||
from cms.utils.i18n import get_public_languages
|
||||
|
||||
default_language = get_public_languages()[0]
|
||||
|
||||
try:
|
||||
clipboard = CascadeClipboard.objects.get(identifier='social-icons')
|
||||
except CascadeClipboard.DoesNotExist:
|
||||
self.stderr.write(
|
||||
"No Persisted Clipboard named 'social-icons' found.")
|
||||
else:
|
||||
static_placeholder = StaticPlaceholder.objects.create(
|
||||
code='Social Icons')
|
||||
deserialize_to_placeholder(
|
||||
static_placeholder.public, clipboard.data, default_language)
|
||||
deserialize_to_placeholder(
|
||||
static_placeholder.draft, clipboard.data, default_language)
|
||||
self.stdout.write("Added Social Icons to Static Placeholder")
|
||||
|
||||
def publish_in_all_languages(self, page):
|
||||
from cms.api import copy_plugins_to_language
|
||||
from cms.utils.i18n import get_public_languages
|
||||
|
||||
languages = get_public_languages()
|
||||
for language in languages[1:]:
|
||||
copy_plugins_to_language(page, languages[0], language)
|
||||
for language in languages:
|
||||
page.publish(language)
|
||||
64
weirdlittleempire/management/commands/download_workdir.py
Normal file
64
weirdlittleempire/management/commands/download_workdir.py
Normal file
@@ -0,0 +1,64 @@
|
||||
import os
|
||||
import requests
|
||||
from io import BytesIO as StringIO
|
||||
from django.conf import settings
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
try:
|
||||
import czipfile as zipfile
|
||||
except ImportError:
|
||||
import zipfile
|
||||
from .spinner import Spinner
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
version = 18
|
||||
help = "Download workdir to run a demo of django-SHOP."
|
||||
download_url = 'https://downloads.django-shop.org/django-shop-workdir-{version}.zip'
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
'--noinput',
|
||||
'--no-input',
|
||||
action='store_false',
|
||||
dest='interactive',
|
||||
default=True,
|
||||
help="Do NOT prompt the user for input of any kind.",
|
||||
)
|
||||
|
||||
def set_options(self, **options):
|
||||
self.interactive = options['interactive']
|
||||
|
||||
def handle(self, verbosity, *args, **options):
|
||||
self.set_options(**options)
|
||||
fixture1 = '{workdir}/fixtures/products-media.json'.format(
|
||||
workdir=settings.WORK_DIR)
|
||||
fixture2 = '{workdir}/fixtures/products-meta.json'.format(
|
||||
workdir=settings.WORK_DIR)
|
||||
if os.path.isfile(fixture1) or os.path.isfile(fixture2):
|
||||
if self.interactive:
|
||||
mesg = """
|
||||
This will overwrite your workdir for your django-SHOP demo.
|
||||
Are you sure you want to do this?
|
||||
|
||||
Type 'yes' to continue, or 'no' to cancel:
|
||||
"""
|
||||
if input(mesg) != 'yes':
|
||||
raise CommandError(
|
||||
"Downloading workdir has been cancelled.")
|
||||
else:
|
||||
self.stdout.write(self.style.WARNING(
|
||||
"Can not override downloaded data in input-less mode."))
|
||||
return
|
||||
|
||||
extract_to = os.path.join(settings.WORK_DIR, os.pardir)
|
||||
msg = "Downloading workdir and extracting to {}. Please wait"
|
||||
self.stdout.write(msg.format(extract_to), ending=' ')
|
||||
with Spinner():
|
||||
download_url = self.download_url.format(version=self.version)
|
||||
response = requests.get(download_url, stream=True)
|
||||
zip_ref = zipfile.ZipFile(StringIO(response.content))
|
||||
try:
|
||||
zip_ref.extractall(extract_to)
|
||||
finally:
|
||||
zip_ref.close()
|
||||
self.stdout.write('- done.')
|
||||
35
weirdlittleempire/management/commands/export_products.py
Normal file
35
weirdlittleempire/management/commands/export_products.py
Normal file
@@ -0,0 +1,35 @@
|
||||
import json
|
||||
from django.conf import settings
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.utils.module_loading import import_string
|
||||
from django.utils.translation import activate
|
||||
from weirdlittleempire.models import Product
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
'-o',
|
||||
'--output',
|
||||
type=str,
|
||||
dest='filename',
|
||||
)
|
||||
|
||||
def handle(self, verbosity, filename, *args, **options):
|
||||
activate(settings.LANGUAGE_CODE)
|
||||
data = []
|
||||
for product in Product.objects.all():
|
||||
ProductModel = ContentType.objects.get(
|
||||
app_label='weirdlittleempire', model=product.product_model)
|
||||
class_name = 'weirdlittleempire.management.serializers.' + \
|
||||
ProductModel.model_class().__name__ + 'Serializer'
|
||||
serializer_class = import_string(class_name)
|
||||
serializer = serializer_class(product, context={'request': None})
|
||||
data.append(serializer.data)
|
||||
dump = json.dumps(data, indent=2)
|
||||
if filename:
|
||||
with open(filename, 'w') as fh:
|
||||
fh.write(dump)
|
||||
else:
|
||||
self.stdout.write(dump)
|
||||
84
weirdlittleempire/management/commands/import_products.py
Normal file
84
weirdlittleempire/management/commands/import_products.py
Normal file
@@ -0,0 +1,84 @@
|
||||
import json
|
||||
import os
|
||||
from cms.utils.copy_plugins import copy_plugins_to
|
||||
from cms.utils.i18n import get_public_languages
|
||||
from django.conf import settings
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.utils.module_loading import import_string
|
||||
from django.utils.translation import activate
|
||||
from cmsplugin_cascade.models import CascadeClipboard
|
||||
from shop.management.utils import deserialize_to_placeholder
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
'filename',
|
||||
nargs='?',
|
||||
default='products-meta.json',
|
||||
)
|
||||
|
||||
def handle(self, verbosity, filename, *args, **options):
|
||||
activate(settings.LANGUAGE_CODE)
|
||||
path = self.find_fixture(filename)
|
||||
if verbosity >= 2:
|
||||
self.stdout.write("Importing products from: {}".format(path))
|
||||
with open(path, 'r') as fh:
|
||||
data = json.load(fh)
|
||||
|
||||
for number, product in enumerate(data, 1):
|
||||
product_model = product.pop('product_model')
|
||||
if product.get('product_code') == "parklake-springfield":
|
||||
continue
|
||||
ProductModel = ContentType.objects.get(
|
||||
app_label='weirdlittleempire', model=product_model)
|
||||
class_name = 'weirdlittleempire.management.serializers.' + \
|
||||
ProductModel.model_class().__name__ + 'Serializer'
|
||||
serializer_class = import_string(class_name)
|
||||
serializer = serializer_class(data=product)
|
||||
assert serializer.is_valid(), serializer.errors
|
||||
instance = serializer.save()
|
||||
self.assign_product_to_catalog(instance)
|
||||
self.stdout.write("{}. {}".format(number, instance))
|
||||
if product_model == 'commodity':
|
||||
languages = get_public_languages()
|
||||
try:
|
||||
clipboard = CascadeClipboard.objects.get(
|
||||
identifier=instance.slug)
|
||||
except CascadeClipboard.DoesNotExist:
|
||||
pass
|
||||
else:
|
||||
deserialize_to_placeholder(
|
||||
instance.placeholder, clipboard.data, languages[0])
|
||||
plugins = list(instance.placeholder.get_plugins(
|
||||
language=languages[0]).order_by('path'))
|
||||
for language in languages[1:]:
|
||||
copy_plugins_to(
|
||||
plugins, instance.placeholder, language)
|
||||
|
||||
def find_fixture(self, filename):
|
||||
if os.path.isabs(filename):
|
||||
fixture_dirs = [os.path.dirname(filename)]
|
||||
fixture_name = os.path.basename(filename)
|
||||
else:
|
||||
fixture_dirs = settings.FIXTURE_DIRS
|
||||
if os.path.sep in os.path.normpath(filename):
|
||||
fixture_dirs = [os.path.join(dir_, os.path.dirname(filename))
|
||||
for dir_ in fixture_dirs]
|
||||
fixture_name = os.path.basename(filename)
|
||||
else:
|
||||
fixture_name = filename
|
||||
for fixture_dir in fixture_dirs:
|
||||
path = os.path.join(fixture_dir, fixture_name)
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
raise CommandError(
|
||||
"No such file in any fixture dir: {}".format(filename))
|
||||
|
||||
def assign_product_to_catalog(self, product):
|
||||
from cms.models.pagemodel import Page
|
||||
from shop.models.related import ProductPageModel
|
||||
|
||||
for page in Page.objects.published().filter(application_urls='CatalogListApp'):
|
||||
ProductPageModel.objects.get_or_create(page=page, product=product)
|
||||
@@ -0,0 +1,26 @@
|
||||
import random
|
||||
from django.core.management.base import BaseCommand
|
||||
from weirdlittleempire.models import Commodity, CommodityInventory, SmartCard, SmartCardInventory, SmartPhoneVariant, SmartPhoneInventory
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Create Inventories for all products using random values."
|
||||
|
||||
def handle(self, verbosity, *args, **options):
|
||||
self.verbosity = verbosity
|
||||
for commodity in Commodity.objects.all():
|
||||
CommodityInventory.objects.create(
|
||||
product=commodity,
|
||||
quantity=random.randint(0, 15)
|
||||
)
|
||||
for smart_card in SmartCard.objects.all():
|
||||
SmartCardInventory.objects.create(
|
||||
product=smart_card,
|
||||
quantity=random.randint(0, 55)
|
||||
)
|
||||
for smart_phone in SmartPhoneVariant.objects.all():
|
||||
SmartPhoneInventory.objects.create(
|
||||
product=smart_phone,
|
||||
quantity=random.randint(0, 8)
|
||||
)
|
||||
self.stdout.write("Created inventories with random quantities.")
|
||||
104
weirdlittleempire/management/commands/initialize_shop_demo.py
Normal file
104
weirdlittleempire/management/commands/initialize_shop_demo.py
Normal file
@@ -0,0 +1,104 @@
|
||||
import os
|
||||
from django.conf import settings
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.core.management import call_command
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
try:
|
||||
import czipfile as zipfile
|
||||
except ImportError:
|
||||
import zipfile
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = _("Initialize the workdir to run the demo of weirdlittleempire.")
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
'--noinput', '--no-input',
|
||||
action='store_false',
|
||||
dest='interactive',
|
||||
default=True,
|
||||
help="Do NOT prompt the user for input of any kind.",
|
||||
)
|
||||
|
||||
def set_options(self, **options):
|
||||
self.interactive = options['interactive']
|
||||
|
||||
def clear_compressor_cache(self):
|
||||
from django.core.cache import caches
|
||||
from django.core.cache.backends.base import InvalidCacheBackendError
|
||||
from compressor.conf import settings
|
||||
|
||||
cache_dir = os.path.join(settings.STATIC_ROOT,
|
||||
settings.COMPRESS_OUTPUT_DIR)
|
||||
if settings.COMPRESS_ENABLED is False or not os.path.isdir(cache_dir) or os.listdir(cache_dir) != []:
|
||||
return
|
||||
try:
|
||||
caches['compressor'].clear()
|
||||
except InvalidCacheBackendError:
|
||||
pass
|
||||
|
||||
def handle(self, verbosity, *args, **options):
|
||||
self.set_options(**options)
|
||||
self.clear_compressor_cache()
|
||||
call_command('migrate')
|
||||
initialize_file = os.path.join(settings.WORK_DIR, '.initialize')
|
||||
if os.path.isfile(initialize_file):
|
||||
self.stdout.write("Initializing project weirdlittleempire")
|
||||
call_command('makemigrations', 'weirdlittleempire')
|
||||
call_command('migrate')
|
||||
os.remove(initialize_file)
|
||||
call_command('loaddata', 'skeleton')
|
||||
call_command('shop', 'check-pages', add_recommended=True)
|
||||
call_command('assign_iconfonts')
|
||||
call_command('create_social_icons')
|
||||
call_command('download_workdir', interactive=self.interactive)
|
||||
call_command('loaddata', 'products-media')
|
||||
call_command('import_products')
|
||||
self.create_polymorphic_subcategories()
|
||||
try:
|
||||
call_command('search_index', action='rebuild', force=True)
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
self.stdout.write("Project weirdlittleempire already initialized")
|
||||
call_command('migrate')
|
||||
|
||||
def create_polymorphic_subcategories(self):
|
||||
from cms.models.pagemodel import Page
|
||||
from shop.management.commands.shop import Command as ShopCommand
|
||||
from weirdlittleempire.models import Commodity, SmartCard, SmartPhoneModel
|
||||
|
||||
apphook = ShopCommand.get_installed_apphook('CatalogListCMSApp')
|
||||
catalog_pages = Page.objects.drafts().filter(
|
||||
application_urls=apphook.__class__.__name__)
|
||||
assert catalog_pages.count() == 1, "There should be only one catalog page"
|
||||
self.create_subcategory(
|
||||
apphook, catalog_pages.first(), "Earphones", Commodity)
|
||||
self.create_subcategory(
|
||||
apphook, catalog_pages.first(), "Smart Cards", SmartCard)
|
||||
self.create_subcategory(
|
||||
apphook, catalog_pages.first(), "Smart Phones", SmartPhoneModel)
|
||||
|
||||
def create_subcategory(self, apphook, parent_page, title, product_type):
|
||||
from cms.api import create_page
|
||||
from cms.constants import TEMPLATE_INHERITANCE_MAGIC
|
||||
from cms.utils.i18n import get_public_languages
|
||||
from shop.management.commands.shop import Command as ShopCommand
|
||||
from shop.models.product import ProductModel
|
||||
from shop.models.related import ProductPageModel
|
||||
|
||||
language = get_public_languages()[0]
|
||||
page = create_page(
|
||||
title,
|
||||
TEMPLATE_INHERITANCE_MAGIC,
|
||||
language,
|
||||
apphook=apphook,
|
||||
created_by="manage.py initialize_shop_demo",
|
||||
in_navigation=True,
|
||||
parent=parent_page,
|
||||
)
|
||||
ShopCommand.publish_in_all_languages(page)
|
||||
page = page.get_public_object()
|
||||
for product in ProductModel.objects.instance_of(product_type):
|
||||
ProductPageModel.objects.create(page=page, product=product)
|
||||
37
weirdlittleempire/management/commands/spinner.py
Normal file
37
weirdlittleempire/management/commands/spinner.py
Normal file
@@ -0,0 +1,37 @@
|
||||
import sys
|
||||
import time
|
||||
import threading
|
||||
|
||||
|
||||
class Spinner:
|
||||
busy = False
|
||||
delay = 0.1
|
||||
|
||||
@staticmethod
|
||||
def spinning_cursor():
|
||||
while 1:
|
||||
for cursor in '|/-\\':
|
||||
yield cursor
|
||||
|
||||
def __init__(self, delay=None):
|
||||
self.spinner_generator = self.spinning_cursor()
|
||||
if delay and float(delay):
|
||||
self.delay = delay
|
||||
|
||||
def spinner_task(self):
|
||||
while self.busy:
|
||||
sys.stdout.write(next(self.spinner_generator))
|
||||
sys.stdout.flush()
|
||||
time.sleep(self.delay)
|
||||
sys.stdout.write('\b')
|
||||
sys.stdout.flush()
|
||||
|
||||
def __enter__(self):
|
||||
self.busy = True
|
||||
threading.Thread(target=self.spinner_task).start()
|
||||
|
||||
def __exit__(self, exception, value, tb):
|
||||
self.busy = False
|
||||
time.sleep(self.delay)
|
||||
if exception is not None:
|
||||
return False
|
||||
68
weirdlittleempire/management/serializers.py
Normal file
68
weirdlittleempire/management/serializers.py
Normal file
@@ -0,0 +1,68 @@
|
||||
"""
|
||||
These serializers are used exclusively to import the file ``workdir/fixtures/products-meta.json``.
|
||||
They are not intended for general purpose and can be deleted thereafter.
|
||||
"""
|
||||
from rest_framework import serializers
|
||||
from shop.serializers.catalog import CMSPagesField, ImagesField, ValueRelatedField
|
||||
from weirdlittleempire.models import (Commodity, SmartCard, SmartPhoneModel, SmartPhoneVariant,
|
||||
Manufacturer, OperatingSystem, ProductPage, ProductImage)
|
||||
from .translation import TranslatedFieldsField, TranslatedField, TranslatableModelSerializerMixin
|
||||
|
||||
|
||||
class ProductSerializer(serializers.ModelSerializer):
|
||||
product_model = serializers.CharField(read_only=True)
|
||||
manufacturer = ValueRelatedField(model=Manufacturer)
|
||||
images = ImagesField()
|
||||
caption = TranslatedField()
|
||||
cms_pages = CMSPagesField()
|
||||
|
||||
class Meta:
|
||||
exclude = ['id', 'polymorphic_ctype', 'updated_at']
|
||||
|
||||
def create(self, validated_data):
|
||||
cms_pages = validated_data.pop('cms_pages')
|
||||
images = validated_data.pop('images')
|
||||
product = super().create(validated_data)
|
||||
for page in cms_pages:
|
||||
ProductPage.objects.create(product=product, page=page)
|
||||
for image in images:
|
||||
ProductImage.objects.create(product=product, image=image)
|
||||
return product
|
||||
|
||||
|
||||
class CommoditySerializer(TranslatableModelSerializerMixin, ProductSerializer):
|
||||
|
||||
class Meta(ProductSerializer.Meta):
|
||||
model = Commodity
|
||||
exclude = ['id', 'placeholder', 'polymorphic_ctype', 'updated_at']
|
||||
|
||||
|
||||
class SmartCardSerializer(TranslatableModelSerializerMixin, ProductSerializer):
|
||||
multilingual = TranslatedFieldsField(
|
||||
help_text="Helper to convert multilingual data into single field.",
|
||||
)
|
||||
|
||||
class Meta(ProductSerializer.Meta):
|
||||
model = SmartCard
|
||||
|
||||
|
||||
class SmartphoneVariantSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = SmartPhoneVariant
|
||||
fields = ['product_code', 'unit_price', 'storage', 'quantity']
|
||||
|
||||
|
||||
class SmartPhoneModelSerializer(TranslatableModelSerializerMixin, ProductSerializer):
|
||||
multilingual = TranslatedFieldsField()
|
||||
operating_system = ValueRelatedField(model=OperatingSystem)
|
||||
variants = SmartphoneVariantSerializer(many=True)
|
||||
|
||||
class Meta(ProductSerializer.Meta):
|
||||
model = SmartPhoneModel
|
||||
|
||||
def create(self, validated_data):
|
||||
variants = validated_data.pop('variants')
|
||||
product = super().create(validated_data)
|
||||
for variant in variants:
|
||||
SmartPhoneVariant.objects.create(product=product, **variant)
|
||||
return product
|
||||
73
weirdlittleempire/management/translation.py
Normal file
73
weirdlittleempire/management/translation.py
Normal file
@@ -0,0 +1,73 @@
|
||||
"""
|
||||
These serializer mixinins and fields are used exclusively to import the file
|
||||
``workdir/fixtures/products-meta.json``. They are not intended for general
|
||||
purpose and can be deleted thereafter.
|
||||
"""
|
||||
from rest_framework import serializers
|
||||
|
||||
|
||||
class TranslatableModelSerializerMixin:
|
||||
"""
|
||||
Pseudo class mimicking the behaviour of :class:`parler_rest.TranslatableModelSerializerMixin`.
|
||||
It converts the content for fields of type TranslatedFieldsField to simple serializer
|
||||
fields.
|
||||
"""
|
||||
|
||||
def to_internal_value(self, data):
|
||||
data = self._unify_translated_data(data)
|
||||
result = super().to_internal_value(data)
|
||||
return result
|
||||
|
||||
def _unify_translated_data(self, data):
|
||||
"""
|
||||
Unify translated data to be used by simple serializer fields.
|
||||
"""
|
||||
for field_name, field in self.get_fields().items():
|
||||
if isinstance(field, TranslatedFieldsField):
|
||||
key = field.source or field_name
|
||||
translations = data.pop(key, None)
|
||||
if isinstance(translations, dict):
|
||||
data.update(translations.get('en', {}))
|
||||
return data
|
||||
|
||||
|
||||
class TranslatedFieldsField(serializers.Field):
|
||||
"""
|
||||
Pseudo class mimicking the behaviour of :class:`parler_rest.TranslatedFieldsField`, where only
|
||||
the English translation is used.
|
||||
"""
|
||||
|
||||
def to_representation(self, value):
|
||||
raise NotImplementedError(
|
||||
"If USE_I18N is False, do not use {cls}.to_representation() for field '{field_name}'. "
|
||||
"It thwarts the possibility to reuse that string in a multi language environment.".format(
|
||||
cls=self.__class__.__name__,
|
||||
field_name=self.field_name,
|
||||
)
|
||||
)
|
||||
|
||||
def validate_empty_values(self, data):
|
||||
raise serializers.SkipField()
|
||||
|
||||
|
||||
class TranslatedField(serializers.Field):
|
||||
"""
|
||||
Pseudo class mimicking the behaviour of :class:`parler_rest.TranslatedField`, where only
|
||||
the English translation is used.
|
||||
"""
|
||||
|
||||
def to_representation(self, value):
|
||||
raise NotImplementedError(
|
||||
"If USE_I18N is False, do not use {cls}.to_representation() for field '{field_name}'. "
|
||||
"It thwarts the possibility to reuse that string in a multi language environment.".format(
|
||||
cls=self.__class__.__name__,
|
||||
field_name=self.field_name,
|
||||
)
|
||||
)
|
||||
|
||||
def to_internal_value(self, data):
|
||||
return data.get('en')
|
||||
|
||||
|
||||
__all__ = ['TranslatedFieldsField', 'TranslatedField',
|
||||
'TranslatableModelSerializerMixin']
|
||||
Reference in New Issue
Block a user