Создать ограничение проверки на основе пользовательской SQL и пользовательской Django функции - PullRequest
0 голосов
/ 06 августа 2020

Вопрос относительно использования настраиваемой функции в проверочном ограничении:

У меня следующая модель:

class UserIP(models.Model):
    user = models.ForeignKey(
        to=User,
        on_delete=models.CASCADE,
        related_name='user_ip',
    )
    ip = models.GenericIPAddressField(
        verbose_name='User ip address'
    )
    sample_time = models.DateTimeField(
        auto_now=True,
        verbose_name='User ip sample time'
    )

и у меня есть следующая настраиваемая функция в базе данных:

create or replace function count_ips(v_ip inet , v_user_id int, v_limit int)
                               returns boolean as $$
                               select count(*) > v_limit
                               from users_userip
                               where ip = v_ip and user_id = v_user_id
                               $$ language sql;

, который возвращает True, если в БД больше X (а значит, 3) записей с одинаковыми ip и user.

На основе этой функции я создал функцию Django, например это:

class IpCount(Func):
    function = 'count_ips'
    arity = 3
    output_field = BooleanField()

пример использования:

UserIP.objects.all().annotate(ann=IpCount(Value('127.0.0.1'), 1,3)).first().ann

отлично работает

Теперь я хочу сделать ограничение проверки, которое не позволило бы сохранить в БД любую новую запись если в БД уже есть 3 или более записей, где user и ip совпадают.


constraints = [
    models.CheckConstraint(
        name='max_3_ips',
        check=~models.Q(IpCount('ip', 'user_id', 3)),
    ), ]

Это говорит тогда, поскольку Django> 3.1. он поддерживает логические выражения внутри ограничений chek c, но то, что я написал, не работает. Ошибка выглядит так:

 File "C:\Users\hardcase1\.virtualenvs\series-EAOB5IHD\lib\site-packages\django\db\models\query_utils.py", line 117, in deconstruct
    kwargs = {child[0]: child[1]}
TypeError: 'IpCount' object is not subscriptable

Похоже, что Django mirations не могут сериализовать эту функцию.

Вопрос - как использовать эту функцию в проверочном ограничении и возможно ли это вообще или мне просто забыть об этом и вместо этого создать настраиваемую миграцию с кучей RAW sQL внутри?

Спасибо

1 Ответ

0 голосов
/ 06 августа 2020

Начиная с django 3.1, можно использовать выражения, возвращающие логическое значение, так что нет смысла использовать Q

models.CheckConstraint(
                name='max_3_ips',
                check=IpCount(models.F('user_id'), models.Value(2)),
            ), ]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...