panels executor

This commit is contained in:
Dmitriy Kuzmenko 2019-12-19 19:07:23 +03:00
parent 6e72c7c0e4
commit a1f06fd0b9
8 changed files with 152 additions and 5 deletions

View File

@ -54,3 +54,16 @@ class PageAdmin(admin.ModelAdmin):
list_display = ('id', '__str__', 'advertisement')
list_filter = ('advertisement__url', 'source')
date_hierarchy = 'created'
@admin.register(models.Footer)
class FooterAdmin(admin.ModelAdmin):
"""Footer admin."""
list_display = ('id', 'site', )
@admin.register(models.Panel)
class PanelAdmin(admin.ModelAdmin):
"""Panel admin."""
list_display = ('id', 'created', )
raw_id_fields = ('user', )

View File

@ -6,14 +6,18 @@ from django.contrib.contenttypes import fields as generic
from django.contrib.contenttypes.models import ContentType
from django.contrib.postgres.fields import JSONField
from django.core.validators import EMPTY_VALUES
from django.db import connections, connection
from django.db import models
from django.db.models import Q
from django.utils.translation import gettext_lazy as _
from rest_framework import exceptions
from configuration.models import TranslationSettings
from location.models import Country
from main import methods
from review.models import Review
from utils.exceptions import UnprocessableEntityError
from utils.methods import dictfetchall
from utils.models import (ProjectBaseMixin, TJSONField, URLImageMixin,
TranslatedFieldsMixin, PlatformMixin)
@ -402,5 +406,85 @@ class Panel(ProjectBaseMixin):
def __str__(self):
return self.name
def execute_query(self):
pass
def execute_query(self, request):
"""Execute query"""
raw = self.query
page = int(request.query_params.get('page', 0))
page_size = int(request.query_params.get('page_size', 10))
if raw:
data = {
"count": 0,
"next": 2,
"previous": None,
"columns": None,
"results": []
}
with connections['default'].cursor() as cursor:
count = self._raw_count(raw)
start = page*page_size
cursor.execute(*self.set_limits(start, page_size))
data["count"] = count
data["next"] = self.get_next_page(count, page, page_size)
data["previous"] = self.get_previous_page(count, page)
data["results"] = dictfetchall(cursor)
data["columns"] = self._raw_columns(cursor)
return data
def get_next_page(self, count, page, page_size):
max_page = count/page_size-1
if not 0 <= page <= max_page:
raise exceptions.NotFound('Invalid page.')
if max_page > page:
return page + 1
return None
def get_previous_page(self, count, page):
if page > 0:
return page - 1
return None
@staticmethod
def _raw_execute(row):
with connections['default'].cursor() as cursor:
try:
cursor.execute(row)
return cursor.execute(row)
except Exception as er:
# TODO: log
raise UnprocessableEntityError()
def _raw_count(self, subquery):
if ';' in subquery:
subquery = subquery.replace(';', '')
_count_query = f"""SELECT count(*) from ({subquery}) as t;"""
# cursor = self._raw_execute(_count_query)
with connections['default'].cursor() as cursor:
cursor.execute(_count_query)
row = cursor.fetchone()
return row[0]
@staticmethod
def _raw_columns(cursor):
columns = [col[0] for col in cursor.description]
return columns
def _raw_page(self, raw, request):
page = request.query_params.get('page', 0)
page_size = request.query_params.get('page_size', 0)
raw = f"""{raw} LIMIT {page_size} OFFSET {page}"""
return raw
def set_limits(self, start, limit, params=tuple()):
limit_offset = ''
new_params = tuple()
if start > 0:
new_params += (start,)
limit_offset = ' OFFSET %s'
if limit is not None:
new_params = (limit,) + new_params
limit_offset = ' LIMIT %s' + limit_offset
params = params + new_params
query = self.query + limit_offset
return query, params

View File

@ -296,3 +296,20 @@ class PanelSerializer(serializers.ModelSerializer):
'user',
'user_id'
]
class PanelExecuteSerializer(serializers.ModelSerializer):
"""Panel execute serializer."""
class Meta:
model = models.Panel
fields = [
'id',
'name',
'display',
'description',
'query',
'created',
'modified',
'user',
'user_id'
]

View File

@ -23,8 +23,8 @@ urlpatterns = [
path('page-types/', views.PageTypeListCreateView.as_view(),
name='page-types-list-create'),
path('panels/', views.PanelsListCreateView.as_view(), name='panels'),
path('panels/<int:pk>/', views.PanelsListCreateView.as_view(), name='panels-rud'),
# path('panels/<int:pk>/execute/', views.PanelsView.as_view(), name='panels-execute')
path('panels/<int:pk>/', views.PanelsRUDView.as_view(), name='panels-rud'),
path('panels/<int:pk>/execute/', views.PanelsExecuteView.as_view(), name='panels-execute')
]

View File

@ -1,11 +1,14 @@
from django.contrib.contenttypes.models import ContentType
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import generics, permissions
from rest_framework.generics import get_object_or_404
from rest_framework.response import Response
from main import serializers
from main.filters import AwardFilter
from main.models import Award, Footer, PageType, Panel
from main.views import SiteSettingsView, SiteListView
from utils.pagination import TestPagination
class AwardLstView(generics.ListCreateAPIView):
@ -106,4 +109,16 @@ class PanelsRUDView(generics.RetrieveUpdateDestroyAPIView):
permissions.IsAdminUser,
)
serializer_class = serializers.PanelSerializer
queryset = Panel.objects.all()
queryset = Panel.objects.all()
class PanelsExecuteView(generics.ListAPIView):
"""Custom panels view."""
permission_classes = (
permissions.IsAdminUser,
)
queryset = Panel.objects.all()
def list(self, request, *args, **kwargs):
panel = get_object_or_404(Panel, id=self.kwargs['pk'])
return Response(panel.execute_query(request))

View File

@ -1239,6 +1239,7 @@ class OwnershipAffs(MigrateMixin):
managed = False
db_table = 'ownership_affs'
class Panels(MigrateMixin):
using = 'legacy'

View File

@ -171,3 +171,11 @@ class RemovedBindingObjectNotFound(serializers.ValidationError):
"""The exception must be thrown if the object not found."""
default_detail = _('Removed binding object not found.')
class UnprocessableEntityError(exceptions.APIException):
"""
The exception should be thrown when executing data on server rise error.
"""
status_code = status.HTTP_422_UNPROCESSABLE_ENTITY
default_detail = _('Unprocessable entity valid.')

View File

@ -132,3 +132,12 @@ def namedtuplefetchall(cursor):
desc = cursor.description
nt_result = namedtuple('Result', [col[0] for col in desc])
return [nt_result(*row) for row in cursor.fetchall()]
def dictfetchall(cursor):
"Return all rows from a cursor as a dict"
columns = [col[0] for col in cursor.description]
return [
dict(zip(columns, row))
for row in cursor.fetchall()
]