refactored product app, see changes

This commit is contained in:
Anatoly 2019-11-05 18:04:34 +03:00
parent d46ba31654
commit 87dacfec7f
13 changed files with 188 additions and 234 deletions

View File

@ -1,52 +0,0 @@
# Generated by Django 2.2.4 on 2019-11-01 13:23
import django.contrib.gis.db.models.fields
from django.db import migrations, models
import utils.models
class Migration(migrations.Migration):
dependencies = [
('location', '0020_merge_20191030_1714'),
]
operations = [
migrations.CreateModel(
name='WineSubRegion',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255, verbose_name='name')),
],
options={
'verbose_name': 'wine region',
'verbose_name_plural': 'wine regions',
},
),
migrations.CreateModel(
name='WineVillage',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255, verbose_name='name')),
('description', utils.models.TJSONField(help_text='{"en-GB":"some text"}', verbose_name='description')),
],
options={
'verbose_name': 'wine village',
'verbose_name_plural': 'wine villages',
},
),
migrations.RemoveField(
model_name='wineappellation',
name='wine_region',
),
migrations.AddField(
model_name='wineregion',
name='coordinates',
field=django.contrib.gis.db.models.fields.PointField(blank=True, default=None, null=True, srid=4326, verbose_name='Coordinates'),
),
migrations.AlterField(
model_name='wineregion',
name='name',
field=models.CharField(max_length=255, verbose_name='name'),
),
]

View File

@ -1,33 +0,0 @@
# Generated by Django 2.2.4 on 2019-11-01 13:23
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('product', '0003_auto_20191101_1323'),
('location', '0021_auto_20191101_1323'),
]
operations = [
migrations.DeleteModel(
name='WineAppellation',
),
migrations.AddField(
model_name='winevillage',
name='wine_region',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='location.WineRegion', verbose_name='wine region'),
),
migrations.AddField(
model_name='winevillage',
name='wine_sub_region',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='location.WineSubRegion', verbose_name='wine sub region'),
),
migrations.AddField(
model_name='winesubregion',
name='country',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='location.Country', verbose_name='country'),
),
]

View File

@ -1,12 +1,19 @@
"""Product admin conf.""" """Product admin conf."""
from django.contrib import admin from django.contrib import admin
from utils.admin import BaseModelAdminMixin from utils.admin import BaseModelAdminMixin
from .models import Product, ProductType, ProductSubType, Unit, Characteristic from .models import Product, ProductType, ProductSubType, Unit, \
Characteristic, ProductCharacteristic
class ProductCharacteristics(admin.TabularInline):
model = ProductCharacteristic
extra = 0
@admin.register(Product) @admin.register(Product)
class ProductAdmin(BaseModelAdminMixin, admin.ModelAdmin): class ProductAdmin(BaseModelAdminMixin, admin.ModelAdmin):
"""Admin page for model Product.""" """Admin page for model Product."""
inlines = [ProductCharacteristics, ]
@admin.register(ProductType) @admin.register(ProductType)

View File

@ -1,106 +0,0 @@
# Generated by Django 2.2.4 on 2019-11-01 13:23
import django.contrib.gis.db.models.fields
from django.db import migrations, models
import django.db.models.deletion
import utils.models
class Migration(migrations.Migration):
dependencies = [
('location', '0021_auto_20191101_1323'),
('product', '0002_product_slug'),
]
operations = [
migrations.CreateModel(
name='Characteristic',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', utils.models.TJSONField(blank=True, help_text='{"en-GB":"some text"}', null=True, verbose_name='name')),
('value', models.CharField(blank=True, max_length=255, null=True, verbose_name='value')),
('priority', models.IntegerField(default=None, null=True, unique=True)),
],
options={
'verbose_name': 'characteristic',
'verbose_name_plural': 'characteristics',
},
bases=(utils.models.TranslatedFieldsMixin, models.Model),
),
migrations.CreateModel(
name='Unit',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255, verbose_name='name')),
('value', models.CharField(max_length=255, verbose_name='value')),
],
options={
'verbose_name': 'unit',
'verbose_name_plural': 'units',
},
),
migrations.CreateModel(
name='WineStandard',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255, verbose_name='name')),
('standard_type', models.CharField(choices=[('Appellation', 'Appellation'), ('Classification', 'Classification'), ('WineQuality', 'Wine quality'), ('YardClassification', 'Yard classification')], max_length=30, verbose_name='standard type')),
('coordinates', django.contrib.gis.db.models.fields.PointField(blank=True, default=None, null=True, srid=4326, verbose_name='Coordinates')),
],
options={
'verbose_name': 'wine standard',
'verbose_name_plural': 'wine standards',
},
),
migrations.RemoveField(
model_name='product',
name='wine_appellation',
),
migrations.AddField(
model_name='product',
name='wine_village',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='location.WineVillage', verbose_name='wine appellation'),
),
migrations.RemoveField(
model_name='product',
name='characteristics',
),
migrations.AlterField(
model_name='product',
name='establishment',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='products', to='establishment.Establishment', verbose_name='establishment'),
),
migrations.AlterField(
model_name='product',
name='name',
field=models.CharField(default=None, max_length=255, null=True, verbose_name='name'),
),
migrations.AlterField(
model_name='productsubtype',
name='index_name',
field=models.CharField(choices=[('rum', 'Rum'), ('other', 'Other'), ('extra brut', 'extra brut'), ('brut', 'brut'), ('brut nature', 'brut nature'), ('demi-sec', 'demi-sec'), ('Extra Dry', 'Extra Dry'), ('dosage zero', 'dosage zero'), ('sec', 'sec'), ('doux', 'doux'), ('moelleux', 'moelleux')], db_index=True, max_length=50, unique=True, verbose_name='Index name'),
),
migrations.CreateModel(
name='WineClassification',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255, verbose_name='name')),
('standard', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='product.WineStandard', verbose_name='standard')),
],
options={
'verbose_name': 'wine classification',
'verbose_name_plural': 'wine classifications',
},
),
migrations.AddField(
model_name='product',
name='wine_standard',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='product.WineStandard', verbose_name='wine standard'),
),
migrations.AddField(
model_name='product',
name='characteristics',
field=models.ManyToManyField(to='product.Characteristic', verbose_name='characteristics'),
),
]

View File

@ -139,6 +139,7 @@ class Product(TranslatedFieldsMixin, BaseAttributes):
description = TJSONField(_('Description'), null=True, blank=True, description = TJSONField(_('Description'), null=True, blank=True,
default=None, help_text='{"en-GB":"some text"}') default=None, help_text='{"en-GB":"some text"}')
characteristics = models.ManyToManyField('Characteristic', characteristics = models.ManyToManyField('Characteristic',
through='ProductCharacteristic',
verbose_name=_('characteristics')) verbose_name=_('characteristics'))
country = models.ManyToManyField('location.Country', country = models.ManyToManyField('location.Country',
verbose_name=_('Country')) verbose_name=_('Country'))
@ -229,23 +230,38 @@ class Unit(models.Model):
return self.name return self.name
class Characteristic(TranslatedFieldsMixin, models.Model): class Characteristic(models.Model):
"""Characteristic model.""" """Characteristic model."""
STR_FIELD_NAME = 'name' name = models.CharField(_('name'), max_length=255)
name = TJSONField(_('name'), null=True, blank=True,
help_text='{"en-GB":"some text"}')
value = models.CharField(max_length=255, null=True, blank=True, value = models.CharField(max_length=255, null=True, blank=True,
verbose_name=_('value')) verbose_name=_('value'))
# unit = models.ForeignKey('Unit', on_delete=models.PROTECT) # unit = models.ForeignKey('Unit', on_delete=models.PROTECT)
priority = models.IntegerField(unique=True, null=True, default=None) priority = models.IntegerField(unique=True, null=True, default=None)
old_id = models.PositiveIntegerField(blank=True, null=True, default=None)
class Meta: class Meta:
"""Meta model.""" """Meta model."""
verbose_name = _('characteristic') verbose_name = _('characteristic')
verbose_name_plural = _('characteristics') verbose_name_plural = _('characteristics')
def __str__(self):
return self.name
class ProductCharacteristic(models.Model):
product = models.ForeignKey('Product', on_delete=models.CASCADE)
characteristic = models.ForeignKey('Characteristic', on_delete=models.CASCADE)
class Meta:
"""Meta class."""
verbose_name = _('product characteristic')
verbose_name_plural = _('product characteristics')
def __str__(self):
return f'{self.characteristic.name} - {self.characteristic.value}'
class WineStandardQuerySet(models.QuerySet): class WineStandardQuerySet(models.QuerySet):
"""Wine appellation queryset.""" """Wine appellation queryset."""
@ -271,6 +287,7 @@ class WineStandard(models.Model):
verbose_name=_('standard type')) verbose_name=_('standard type'))
coordinates = gis_models.PointField( coordinates = gis_models.PointField(
_('Coordinates'), blank=True, null=True, default=None) _('Coordinates'), blank=True, null=True, default=None)
old_id = models.PositiveIntegerField(_('old id'), blank=True, null=True, default=None)
objects = WineStandardQuerySet.as_manager() objects = WineStandardQuerySet.as_manager()
@ -289,6 +306,12 @@ class WineClassification(models.Model):
name = models.CharField(_('name'), max_length=255) name = models.CharField(_('name'), max_length=255)
standard = models.ForeignKey(WineStandard, on_delete=models.PROTECT, standard = models.ForeignKey(WineStandard, on_delete=models.PROTECT,
verbose_name=_('standard')) verbose_name=_('standard'))
possible_color = models.ForeignKey(Characteristic, on_delete=models.PROTECT,
help_text=_('Legacy attribute'))
possible_subtype = models.ForeignKey(ProductSubType, on_delete=models.PROTECT,
blank=True, null=True, default=None,
help_text=_('Legacy attribute - possible_type'))
old_id = models.PositiveIntegerField(_('old id'), blank=True, null=True, default=None)
objects = WineClassificationQuerySet.as_manager() objects = WineClassificationQuerySet.as_manager()

View File

@ -1,12 +1,12 @@
from pprint import pprint from pprint import pprint
from transfer.models import EstablishmentBacklinks, WineColor from transfer import models as transfer_models
from transfer.serializers.partner import PartnerSerializer from transfer.serializers.partner import PartnerSerializer
from transfer.serializers.product import WineColorSerializer from transfer.serializers import product as product_serializers
def transfer_partner(): def transfer_partner():
queryset = EstablishmentBacklinks.objects.filter(type="Partner") queryset = transfer_models.EstablishmentBacklinks.objects.filter(type="Partner")
serialized_data = PartnerSerializer(data=list(queryset.values()), many=True) serialized_data = PartnerSerializer(data=list(queryset.values()), many=True)
if serialized_data.is_valid(): if serialized_data.is_valid():
@ -16,16 +16,41 @@ def transfer_partner():
def transfer_wine_color(): def transfer_wine_color():
queryset = WineColor.objects.all() queryset = transfer_models.WineColor.objects.all()
serialized_data = WineColorSerializer(data=list(queryset.values()), serialized_data = product_serializers.WineColorSerializer(
many=True) data=list(queryset.values()),
many=True)
if serialized_data.is_valid(): if serialized_data.is_valid():
serialized_data.save() serialized_data.save()
else: else:
pprint(f"CharacteristicSerializer errors: {serialized_data.errors}") pprint(f"WineColorSerializer errors: {serialized_data.errors}")
def transfer_wine_standard():
queryset = transfer_models.WineClassification.objects.filter(parent_id__isnull=True)
serialized_data = product_serializers.WineStandardSerializer(
data=list(queryset.values()),
many=True)
if serialized_data.is_valid():
serialized_data.save()
else:
pprint(f"WineStandardSerializer errors: {serialized_data.errors}")
def transfer_wine_classifications():
queryset = transfer_models.WineClassification.objects.filter(parent_id__isnull=False)
serialized_data = product_serializers.WineStandardClassificationSerializer(
data=list(queryset.values()),
many=True)
if serialized_data.is_valid():
serialized_data.save()
else:
pprint(f"WineStandardClassificationSerializer errors: {serialized_data.errors}")
data_types = { data_types = {
"partner": [transfer_partner], "partner": [transfer_partner],
"wine_color": [transfer_wine_color], "wine_color": [transfer_wine_color],
"wine_standard": [transfer_wine_standard],
"wine_classification": [transfer_wine_classifications],
} }

View File

@ -27,6 +27,9 @@ class Command(BaseCommand):
LONG_DATA_TYPES = [ LONG_DATA_TYPES = [
'update_country_flag', 'update_country_flag',
'wine_color',
'wine_standard',
'wine_classification',
] ]
def handle(self, *args, **options): def handle(self, *args, **options):

View File

@ -909,6 +909,16 @@ class WineColor(MigrateMixin):
db_table = 'wine_colors' db_table = 'wine_colors'
class WineType(MigrateMixin):
using = 'legacy'
name = models.CharField(max_length=255)
class Meta:
managed = False
db_table = 'wine_types'
class WineClassification(MigrateMixin): class WineClassification(MigrateMixin):
using = 'legacy' using = 'legacy'
@ -927,17 +937,6 @@ class WineClassification(MigrateMixin):
db_table = 'wine_classifications' db_table = 'wine_classifications'
class WineTypes(MigrateMixin):
using = 'legacy'
name = models.CharField(max_length=255, blank=True, null=True)
fra_encima_id = models.IntegerField(blank=True, null=True)
class Meta:
managed = False
db_table = 'wine_types'
# class Products(models.Model): # class Products(models.Model):
# establishment = models.ForeignKey('Establishments', models.DO_NOTHING, blank=True, null=True) # establishment = models.ForeignKey('Establishments', models.DO_NOTHING, blank=True, null=True)
# brand = models.CharField(max_length=255, blank=True, null=True) # brand = models.CharField(max_length=255, blank=True, null=True)

View File

@ -1,17 +1,21 @@
from django.contrib.gis.db.models.fields import Point
from rest_framework import serializers from rest_framework import serializers
from product.models import Characteristic from product import models
from transfer.models import WineColor, WineType, WineClassification
class WineColorSerializer(serializers.ModelSerializer): class WineColorSerializer(serializers.ModelSerializer):
NAME = 'Wine color' NAME = 'wine_color'
id = serializers.IntegerField()
name = serializers.CharField(allow_null=True) name = serializers.CharField(allow_null=True)
order_number = serializers.IntegerField(allow_null=True) order_number = serializers.IntegerField(allow_null=True)
class Meta: class Meta:
model = Characteristic model = models.Characteristic
fields = ( fields = (
'id',
'name', 'name',
'value', 'value',
'priority', 'priority',
@ -19,8 +23,87 @@ class WineColorSerializer(serializers.ModelSerializer):
) )
def validate(self, attrs): def validate(self, attrs):
attrs['old_id'] = attrs.pop('id')
attrs['value'] = attrs['name'] attrs['value'] = attrs['name']
attrs['name'] = {'en-GB': self.NAME} attrs['name'] = self.NAME
attrs['priority'] = attrs['order_number'] attrs['priority'] = attrs.pop('order_number')
attrs.pop('order_number')
return attrs return attrs
class WineStandardSerializer(serializers.ModelSerializer):
id = serializers.IntegerField()
name = serializers.CharField()
type = serializers.ChoiceField(choices=models.WineStandard.STANDARDS,
allow_null=True)
longitude = serializers.FloatField(allow_null=True)
latitude = serializers.FloatField(allow_null=True)
class Meta:
model = models.WineStandard
fields = (
'id',
'name',
'type',
'longitude',
'latitude',
)
def validate(self, attrs):
latitude = attrs.pop('latitude', None)
longitude = attrs.pop('longitude', None)
attrs['coordinates'] = self.get_point(latitude, longitude)
attrs['old_id'] = attrs.get('id')
attrs['standard_type'] = attrs.pop('type', None)
return attrs
def get_point(self, latitude, longitude):
if latitude and longitude:
return Point(x=longitude, y=latitude, srid=4326)
class WineStandardClassificationSerializer(serializers.ModelSerializer):
id = serializers.IntegerField()
name = serializers.CharField()
possible_type_id = serializers.IntegerField(allow_null=True)
possible_color_id = serializers.IntegerField()
parent_id = serializers.IntegerField()
class Meta:
model = models.WineClassification
fields = (
'id',
'name',
'possible_type_id',
'possible_color_id',
'parent_id',
)
def validate(self, attrs):
possible_type_id = attrs.pop('possible_type_id', None)
possible_color_id = attrs.pop('possible_color_id', None)
parent_id = attrs.pop('parent_id', None)
attrs['old_id'] = attrs.pop('id', None)
attrs['possible_subtype'] = self.get_possible_type(possible_type_id)
attrs['possible_color'] = self.get_possible_color(possible_color_id)
attrs['standard'] = self.get_wine_standard(parent_id)
return attrs
def get_possible_type(self, possible_type_id):
legacy_qs = WineClassification.objects.filter(id=possible_type_id)
if legacy_qs.exists():
qs = models.ProductSubType.objects.filter(index_name=legacy_qs.first())
if qs.exists():
return qs.first()
def get_possible_color(self, possible_color_id):
qs = models.Characteristic.objects.filter(name=WineColorSerializer.NAME,
old_id=possible_color_id)
if qs.exists():
return qs.first()
def get_wine_standard(self, parent_id):
qs = models.WineStandard.objects.filter(old_id=parent_id)
if qs.exists():
return qs.first()

View File

@ -74,7 +74,6 @@ PROJECT_APPS = [
'comment.apps.CommentConfig', 'comment.apps.CommentConfig',
'favorites.apps.FavoritesConfig', 'favorites.apps.FavoritesConfig',
'rating.apps.RatingConfig', 'rating.apps.RatingConfig',
# 'transfer.apps.TransferConfig',
'tag.apps.TagConfig', 'tag.apps.TagConfig',
'product.apps.ProductConfig', 'product.apps.ProductConfig',
] ]
@ -157,16 +156,6 @@ DATABASES = {
'HOST': os.environ.get('DB_HOSTNAME'), 'HOST': os.environ.get('DB_HOSTNAME'),
'PORT': os.environ.get('DB_PORT'), 'PORT': os.environ.get('DB_PORT'),
}, },
# 'legacy': {
# 'ENGINE': 'django.db.backends.mysql',
# # 'HOST': '172.17.0.1',
# # 'HOST': '172.23.0.1',
# 'HOST': 'mysql_db',
# 'PORT': 3306,
# 'NAME': 'dev',
# 'USER': 'dev',
# 'PASSWORD': 'octosecret123'
# }
} }

View File

@ -34,6 +34,22 @@ MEDIA_ROOT = os.path.join(PUBLIC_ROOT, MEDIA_LOCATION)
# SORL thumbnails # SORL thumbnails
THUMBNAIL_DEBUG = True THUMBNAIL_DEBUG = True
# ADDED TRANSFER APP
INSTALLED_APPS.append('transfer.apps.TransferConfig')
# ADDED LEGACY DB CONNECTOR
DATABASES.update({
'legacy': {
'ENGINE': 'django.db.backends.mysql',
# 'HOST': '172.17.0.1',
# 'HOST': '172.23.0.1',
'HOST': 'mysql_db',
'PORT': 3306,
'NAME': 'dev',
'USER': 'dev',
'PASSWORD': 'octosecret123'}})
# LOGGING # LOGGING
LOGGING = { LOGGING = {

View File

@ -42,7 +42,6 @@ django-storages==1.7.2
sorl-thumbnail==12.5.0 sorl-thumbnail==12.5.0
# mysqlclient==1.4.4
PyYAML==5.1.2 PyYAML==5.1.2
# temp solution # temp solution

View File

@ -1,3 +1,4 @@
-r base.txt -r base.txt
ipdb ipdb
ipython ipython
mysqlclient==1.4.4