From b03cd4fe0951e6529ba2a6ed8eb089105fbc7b28 Mon Sep 17 00:00:00 2001 From: Dmitriy Kuzmenko Date: Thu, 12 Dec 2019 15:37:42 +0300 Subject: [PATCH] add transfer command, models and crud api. --- apps/main/management/commands/add_panels.py | 38 ++++++++++++++++ apps/main/migrations/0042_panel.py | 36 ++++++++++++++++ apps/main/models.py | 43 +++++++++++++++++++ apps/main/serializers.py | 28 +++++++++++- apps/main/urls/back.py | 6 ++- apps/main/views/back.py | 20 ++++++++- .../migrations/0021_auto_20191212_0926.py | 19 ++++++++ apps/transfer/models.py | 17 ++++++++ apps/utils/methods.py | 8 ++++ 9 files changed, 212 insertions(+), 3 deletions(-) create mode 100644 apps/main/management/commands/add_panels.py create mode 100644 apps/main/migrations/0042_panel.py create mode 100644 apps/product/migrations/0021_auto_20191212_0926.py diff --git a/apps/main/management/commands/add_panels.py b/apps/main/management/commands/add_panels.py new file mode 100644 index 00000000..85e50616 --- /dev/null +++ b/apps/main/management/commands/add_panels.py @@ -0,0 +1,38 @@ +from django.core.management.base import BaseCommand +from tqdm import tqdm + +from account.models import User +from main.models import Panel, SiteSettings +from transfer.models import Panels + + +class Command(BaseCommand): + help = '''Add panels from legacy DB.''' + + def handle(self, *args, **kwargs): + objects = [] + deleted = 0 + panels_list = Panels.objects.filter(name__isnull=False) + # remove existing panel + exist_panel = Panel.objects.filter(old_id__isnull=False) + if exist_panel.exists(): + deleted = exist_panel.count() + exist_panel.delete() + + for old_panel in tqdm(panels_list, desc='Add panels'): + site = SiteSettings.objects.filter(old_id=old_panel.site_id).first() + user = User.objects.filter(old_id=old_panel.site_id).first() + if site: + new_panel = Panel( + old_id=old_panel.id, + user=user, + site=site, + name=old_panel.name, + display=old_panel.display, + description=old_panel.description, + query=old_panel.query, + ) + objects.append(new_panel) + Panel.objects.bulk_create(objects) + self.stdout.write( + self.style.WARNING(f'Created {len(objects)}/Deleted {deleted} footer objects.')) diff --git a/apps/main/migrations/0042_panel.py b/apps/main/migrations/0042_panel.py new file mode 100644 index 00000000..3b2da2a0 --- /dev/null +++ b/apps/main/migrations/0042_panel.py @@ -0,0 +1,36 @@ +# Generated by Django 2.2.7 on 2019-12-12 12:00 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('main', '0041_auto_20191211_0631'), + ] + + operations = [ + migrations.CreateModel( + name='Panel', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created', models.DateTimeField(default=django.utils.timezone.now, editable=False, verbose_name='Date created')), + ('modified', models.DateTimeField(auto_now=True, verbose_name='Date updated')), + ('name', models.CharField(max_length=255, verbose_name='name')), + ('display', models.CharField(blank=True, choices=[('table', 'table'), ('table', 'mailing')], default=None, max_length=255, null=True, verbose_name='display')), + ('description', models.CharField(blank=True, default=None, max_length=255, null=True, verbose_name='description')), + ('query', models.TextField(blank=True, default=None, null=True, verbose_name='query')), + ('old_id', models.IntegerField(blank=True, default=None, null=True, verbose_name='old id')), + ('site', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='main.SiteSettings', verbose_name='site')), + ('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='user')), + ], + options={ + 'verbose_name': 'panel', + 'verbose_name_plural': 'panels', + }, + ), + ] diff --git a/apps/main/models.py b/apps/main/models.py index ae4168ea..b39a6037 100644 --- a/apps/main/models.py +++ b/apps/main/models.py @@ -361,3 +361,46 @@ class Footer(ProjectBaseMixin): ) about_us = models.TextField(_('about_us')) copyright = models.TextField(_('copyright')) + + +class PanelQuerySet(models.QuerySet): + """Panels QuerySet.""" + + +class Panel(ProjectBaseMixin): + """Custom panel model with stored SQL query.""" + TABLE = 'table' + MAILING = 'table' + + DISPLAY_CHOICES = ( + (TABLE, _('table')), + (MAILING, _('mailing')) + ) + name = models.CharField(_('name'), max_length=255) + display = models.CharField( + _('display'), max_length=255, choices=DISPLAY_CHOICES, + blank=True, null=True, default=None + ) + description = models.CharField( + _('description'), max_length=255, blank=True, null=True, default=None) + query = models.TextField(_('query'), blank=True, null=True, default=None) + user = models.ForeignKey( + 'account.User', verbose_name=_('user'), null=True, + on_delete=models.SET_NULL) + site = models.ForeignKey( + 'main.SiteSettings', verbose_name=_('site'), null=True, + on_delete=models.SET_NULL) + old_id = models.IntegerField( + _('old id'), null=True, blank=True, default=None) + + objects = PanelQuerySet.as_manager() + + class Meta: + verbose_name = _('panel') + verbose_name_plural = _('panels') + + def __str__(self): + return self.name + + def execute_query(self): + pass diff --git a/apps/main/serializers.py b/apps/main/serializers.py index d586d71a..39c51845 100644 --- a/apps/main/serializers.py +++ b/apps/main/serializers.py @@ -5,6 +5,8 @@ from rest_framework import serializers from location.serializers import CountrySerializer from main import models from utils.serializers import ProjectModelSerializer, TranslatedField, RecursiveFieldSerializer +from account.serializers.back import BackUserSerializer +from account.models import User class FeatureSerializer(serializers.ModelSerializer): @@ -265,8 +267,32 @@ class PageTypeBaseSerializer(serializers.ModelSerializer): class ContentTypeBackSerializer(serializers.ModelSerializer): - """Serializer fro model ContentType.""" + """Serializer for model ContentType.""" class Meta: model = ContentType fields = '__all__' + + +class PanelSerializer(serializers.ModelSerializer): + """Serializer for Custom panel.""" + user_id = serializers.PrimaryKeyRelatedField( + queryset=User.objects.all(), + source='user', + write_only=True + ) + user = BackUserSerializer(read_only=True) + + class Meta: + model = models.Panel + fields = [ + 'id', + 'name', + 'display', + 'description', + 'query', + 'created', + 'modified', + 'user', + 'user_id' + ] diff --git a/apps/main/urls/back.py b/apps/main/urls/back.py index b4e196a3..26afd1a6 100644 --- a/apps/main/urls/back.py +++ b/apps/main/urls/back.py @@ -21,7 +21,11 @@ urlpatterns = [ path('footer/', views.FooterBackView.as_view(), name='footer-list-create'), path('footer//', views.FooterRUDBackView.as_view(), name='footer-rud'), path('page-types/', views.PageTypeListCreateView.as_view(), - name='page-types-list-create') + name='page-types-list-create'), + path('panels/', views.PanelsListCreateView.as_view(), name='panels'), + path('panels//', views.PanelsListCreateView.as_view(), name='panels-rud'), + # path('panels//execute/', views.PanelsView.as_view(), name='panels-execute') + ] diff --git a/apps/main/views/back.py b/apps/main/views/back.py index f6f987af..0a2b7377 100644 --- a/apps/main/views/back.py +++ b/apps/main/views/back.py @@ -4,7 +4,7 @@ from rest_framework import generics, permissions from main import serializers from main.filters import AwardFilter -from main.models import Award, Footer, PageType +from main.models import Award, Footer, PageType, Panel from main.views import SiteSettingsView, SiteListView @@ -89,3 +89,21 @@ class PageTypeListCreateView(generics.ListCreateAPIView): pagination_class = None serializer_class = serializers.PageTypeBaseSerializer queryset = PageType.objects.all() + + +class PanelsListCreateView(generics.ListCreateAPIView): + """Custom panels view.""" + permission_classes = ( + permissions.IsAdminUser, + ) + serializer_class = serializers.PanelSerializer + queryset = Panel.objects.all() + + +class PanelsRUDView(generics.RetrieveUpdateDestroyAPIView): + """Custom panels view.""" + permission_classes = ( + permissions.IsAdminUser, + ) + serializer_class = serializers.PanelSerializer + queryset = Panel.objects.all() \ No newline at end of file diff --git a/apps/product/migrations/0021_auto_20191212_0926.py b/apps/product/migrations/0021_auto_20191212_0926.py new file mode 100644 index 00000000..749ffa08 --- /dev/null +++ b/apps/product/migrations/0021_auto_20191212_0926.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.7 on 2019-12-12 09:26 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('product', '0020_merge_20191209_0911'), + ] + + operations = [ + migrations.AlterField( + model_name='product', + name='product_type', + field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='products', to='product.ProductType', verbose_name='Type'), + ), + ] diff --git a/apps/transfer/models.py b/apps/transfer/models.py index d8268d6d..7f640a5c 100644 --- a/apps/transfer/models.py +++ b/apps/transfer/models.py @@ -1222,3 +1222,20 @@ class Footers(MigrateMixin): class Meta: managed = False db_table = 'footers' + + +class Panels(MigrateMixin): + using = 'legacy' + + name = models.CharField(max_length=255, blank=True, null=True) + display = models.CharField(max_length=255, blank=True, null=True) + description = models.CharField(max_length=255, blank=True, null=True) + query = models.TextField(blank=True, null=True) + created_at = models.DateTimeField(blank=True, null=True) + updated_at = models.DateTimeField(blank=True, null=True) + account_id = models.IntegerField(blank=True, null=True) + site_id = models.IntegerField(blank=True, null=True) + + class Meta: + managed = False + db_table = 'panels' diff --git a/apps/utils/methods.py b/apps/utils/methods.py index dc027317..227bd1ee 100644 --- a/apps/utils/methods.py +++ b/apps/utils/methods.py @@ -3,6 +3,7 @@ import logging import random import re import string +from collections import namedtuple import requests from django.conf import settings @@ -124,3 +125,10 @@ def absolute_url_decorator(func): def get_point_from_coordinates(latitude: str, longitude: str): if latitude and longitude: return Point(x=longitude, y=latitude, srid=4326) + + +def namedtuplefetchall(cursor): + """Return all rows from a cursor as a namedtuple.""" + desc = cursor.description + nt_result = namedtuple('Result', [col[0] for col in desc]) + return [nt_result(*row) for row in cursor.fetchall()]