N
N
NyxDeveloper2020-12-28 16:36:31
Django
NyxDeveloper, 2020-12-28 16:36:31

Error binding parameter 5 - probably unsupported type?

I'm logging changes to tables on the site, this error pops up:
Error binding parameter 5 - probably unsupported type
Without the logger, everything works fine, but nothing works when trying to log.
I went through the debugger, but I can’t understand where I messed up the data type, maybe I didn’t mess it up, of course, I just want to know where the error is.

Editing an object:

def editContactView(request):
    if request.method == 'POST':
        form = EditContactForm(request.POST)
        if form.is_valid():
            old = Contact.objects.get(id=form.cleaned_data['KEY'])
            new = Contact()
            if form.cleaned_data['type']:
                new.type = form.cleaned_data['type']
            else:
                new.type = old.type
            if form.cleaned_data['subject']:
                new.subject = form.cleaned_data['subject']
            else:
                new.subject = old.subject
            if form.cleaned_data['info']:
                new.info = form.cleaned_data['info']
            else:
                new.info = old.info
            if form.cleaned_data['file']:
                new.file = form.cleaned_data['file']

            new.id = old.id
            old.delete()
            new.save()

            return HttpResponseRedirect('/contacts/')
    return HttpResponseRedirect('/contacts/')


middleware:
class Singleton(object):
    """Синглтон"""

    def __new__(cls):
        if not hasattr(cls, 'instance'):
            cls.instance = super(Singleton, cls).__new__(cls)
        return cls.instance


class LoggedInUser(Singleton):
    """Синглтон для хранения пользователя,
    от имени которого выполняется запрос"""
    __metaclass__ = Singleton

    request = None
    user = None
    address = None

    def set_data(self, request):
        self.request = id(request)
        if request.user.is_authenticated:
            self.user = request.user
            self.address = request.META.get('REMOTE_ADDR')

    @property
    def current_user(self):
        return self.user

    @property
    def have_user(self):
        return not self.user is None


class LoggedInUserMiddleware(object):
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        """
        Инициализирует синглтон LoggedInUser
        """
        logged_in_user = LoggedInUser()
        logged_in_user.set_data(request)

        response = self.get_response(request)

        return response


Mixin for logged models:
from django.db import models


class ChangeloggableMixin(models.Model):
    """Значения полей сразу после инициализации объекта"""
    _original_values = None

    class Meta:
        abstract = True

    def __init__(self, *args, **kwargs):
        super(ChangeloggableMixin, self).__init__(*args, **kwargs)

        self._original_values = {
            field.name: getattr(self, field.name)
            for field in self._meta.fields if field.name not in ['added', 'changed'] and hasattr(self, field.name)
        }

    def get_changed_fields(self):
        """
        Получаем измененные данные
        """
        result = {}
        for name, value in self._original_values.items():
            if value != getattr(self, name):
                temp = {}
                temp[name] = getattr(self, name)
                result.update(temp)
        return result


Log class:
from django.db import models
from django.conf import settings
from django.utils.translation import gettext_lazy as _
from django.contrib.postgres.fields import JSONField

ACTION_CREATE = 'create'
ACTION_UPDATE = 'update'
ACTION_DELETE = 'delete'


class ChangeLog(models.Model):
    TYPE_ACTION_ON_MODEL = (
        (ACTION_CREATE, _('Создание')),
        (ACTION_UPDATE, _('Изменение')),
        (ACTION_DELETE, _('Удаление')),
    )
    changed = models.DateTimeField(auto_now=True, verbose_name=u'Дата/время изменения')
    model = models.CharField(max_length=255, verbose_name=u'Таблица', null=True)
    record_id = models.IntegerField(verbose_name=u'ID записи', null=True)
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL, verbose_name=u'Автор изменения',
        on_delete=models.CASCADE, null=True)
    action_on_model = models.CharField(
        choices=TYPE_ACTION_ON_MODEL, max_length=50, verbose_name=u'Действие', null=True)
    data = JSONField(verbose_name=u'Изменяемые данные модели', default=dict)
    ipaddress = models.CharField(max_length=15, verbose_name=u'IP адресс', null=True)

    class Meta:
        ordering = ('changed',)
        verbose_name = _('Change log')
        verbose_name_plural = _('Change logs')

    def __str__(self):
        return f'{self.id}'

    @classmethod
    def add(cls, instance, user, ipaddress, action_on_model, data, id=None):
        """Создание записи в журнале регистрации изменений"""
        log = ChangeLog.objects.get(id=id) if id else ChangeLog()
        log.model = instance.__class__.__name__
        log.record_id = instance.pk
        if user:
            log.user = user
        log.ipaddress = ipaddress
        log.action_on_model = action_on_model
        log.data = data
        log.save()
        return log.pk


Signals:
import time
import json
import datetime

from changelog.middleware import LoggedInUser
from changelog.models import ChangeLog, ACTION_CREATE, ACTION_UPDATE, ACTION_DELETE
from changelog.mixins import ChangeloggableMixin


def journal_save_handler(sender, instance, created, **kwargs):
    if isinstance(instance, ChangeloggableMixin):
        loggedIn = LoggedInUser()
        last_saved = get_last_saved(loggedIn.request, instance)
        changed = merge(last_saved['changed'], instance.get_changed_fields())
        if changed:
            changed = json.loads(json_dumps(changed))
            if created:
                ChangeLog.add(instance, loggedIn.current_user, loggedIn.address, ACTION_CREATE, changed,
                              id=last_saved['id'])
            else:
                ChangeLog.add(instance, loggedIn.current_user, loggedIn.address, ACTION_UPDATE, changed,
                              id=last_saved['id'])


def journal_delete_handler(sender, instance, using, **kwargs):
    if isinstance(instance, ChangeloggableMixin):
        loggedIn = LoggedInUser()
        last_saved = get_last_saved(loggedIn.request, instance)
        ChangeLog.add(instance, loggedIn.current_user, loggedIn.address, ACTION_DELETE, {}, id=last_saved['id'])

def json_dumps(value):
    return json.dumps(value, default=json_handler)

def json_handler(x):
    if isinstance(x, datetime.datetime):
        return x.isoformat()
    return repr(x)

_last_saved = {}

def get_last_saved(request, instance):
    last_saved = _last_saved[request] if request in _last_saved else None
    if not last_saved or last_saved['instance'].__class__ != instance.__class__ or last_saved['instance'].id != instance.id:
        last_saved = {
            'instance': instance,
            'changed': {},
            'id': None,
            'timestamp': time.time()
        }
        _last_saved[request] = last_saved
    return last_saved


def merge(o1, o2):
    for key in o2:
        val2 = o2[key]
        if isinstance(val2, dict) and key in o1:
            val1 = o1[key]
            for k in val2:
                val1[k] = val2[k]
        else:
            o1[key] = val2
    return o1

Answer the question

In order to leave comments, you need to log in

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question