Как хранить комплексное число в модели Django - PullRequest
2 голосов
/ 18 марта 2019

Мне нужно хранить комплексное число в модели Django.Для тех, кто забывает, это просто означает Z=R+jX, где R и X - действительные числа, представляющие действительные и мнимые компоненты комплекса.Будут отдельные номера, а также списки, которые нужно хранить.Мои поиски до сих пор не дали хорошего решения для списков, поэтому я намерен разрешить базе данных обрабатывать список как отдельные записи.

Я вижу два варианта хранения комплексного числа:

1) создайте настраиваемое поле: class Complex(models.CharField) Это позволило бы мне настроить все аспекты поля, но это требует дополнительной работы для проверки, если это нужно сделать правильно.Главный плюс в том, что одно число представлено одним полем в таблице.

2) пусть каждое комплексное число будет представлено строкой, с полем float для действительной части, R, идругое поле float для мнимой части, X. Недостатком этого подхода является то, что мне нужно написать несколько преобразователей, которые будут создавать комплексное число из компонентов, и наоборот.Положительным моментом является то, что база данных просто увидит ее как еще одну запись.

Конечно, эта проблема была решена в прошлом, но я не могу найти хороших ссылок, не говоря уж о какой-то конкретной информации о Джанго.

Это моя первая трещина на месторождении, она основана на другом примере, который я обнаружил, который включал несколько манипуляций со струнами.Что мне неясно, так это то, как и где должны выполняться различные проверки (например, приведение простого числа к сложному числу путем добавления + 0j).Я намерен также добавить функциональность формы, чтобы поле работало как поле с плавающей точкой, но с дополнительными ограничениями или требованиями.

Я еще не тестировал этот код, поэтому могут возникнуть проблемы с ним.Он основан на коде из ответа на этот вопрос SO.После выполнения кода появляется сообщение о том, что в именах методов произошли некоторые изменения.

Какой самый эффективный способ сохранить список в моделях Django?

class ComplexField(models.CharField):

    description = 'A complex number represented as a string'

    def __init__(self, *args, **kwargs):
        kwargs['verbose_name'] = 'Complex Number'
        kwargs['max_length'] = 64
        kwargs['default'] = '0+0j'

        super().__init__(*args, **kwargs)

    def to_python(self, value):
        if not value: return
        if isinstance(value, complex):
            return value
        return complex(value)

    def get_db_prep_value(self, value):
        if not value: return
        assert(isinstance(value, complex))
        return str(item)[1:-1]

    def value_to_string(self, obj):
        value = self._get_val_from_obj(obj)
        return self.get_db_prep_value(value)

Ответы [ 3 ]

1 голос
/ 19 марта 2019

Что касается пользовательских полей, вы, вероятно, уже нашли соответствующую часть в документации Django .

Вопрос о том, стоит ли создавать пользовательское поле (или пользовательский тип базы данных, см. Ниже), действительно зависит от того, что вам нужно делать с сохраненными числами.Для хранения и некоторых случайных перемещений вы можете использовать самое простое и вменяемое решение (ваш номер два улучшен в Tobit).

С PostgreSQL у вас есть возможность реализовывать пользовательские типы непосредственно в базе данных, включая операторы .Вот соответствующая часть в Документах Postgres , в комплекте с примером комплексных чисел, не менее.

Конечно, тогда вам нужно представить новый тип и операторы Django.Довольно много работы, но тогда вы можете выполнять арифметику с отдельными полями прямо в базе данных, используя Django ORM.

1 голос
/ 19 марта 2019

Если ваше выражение каждый раз, как R + jX, вы можете сделать следующий класс

class ComplexNumber(models.Model):
    real_number = models.FloatField('Real number part')
    img_number = models.FloatFoeld('Img number part')

    def __str__(self):
        return complex(self.real_number, self.img_number)

и обработать строку результата с помощью python см. Здесь

Если выиметь несколько реальных и img-частей, вы можете справиться с этим с помощью внешних ключей или полей ManyToMany.Это может зависеть от ваших потребностей.

0 голосов
/ 19 марта 2019

Если честно, я бы просто разделил комплексное число на два поля с плавающей запятой / десятичное поле и добавил свойство для чтения и записи в виде одного комплексного числа.

Я придумал это настраиваемое поле, которое заканчивается как поле разделения на фактической модели и также добавляет вышеупомянутое свойство.

NB. Я не проверял это за пределами миграций, поэтому все может быть неожиданно сломано, но, по крайней мере, теория обоснована. :)

from django.db import models


class ComplexField(models.Field):
    def __init__(self, **kwargs):
        self.field_class = kwargs.pop('field_class', models.FloatField)
        self.field_kwargs = kwargs.pop('field_kwargs', {})
        super().__init__(**kwargs)

    def contribute_to_class(self, cls, name, private_only=False):
        for field in (
            self.field_class(name=name + '_real', **self.field_kwargs),
            self.field_class(name=name + '_imag', **self.field_kwargs),
        ):
            field.contribute_to_class(cls, field.name)

        setattr(cls, name, ComplexProperty(name))


class ComplexProperty:
    def __init__(self, name):
        self.name = name

    def __get__(self, instance, owner):
        if not instance:
            return self
        real = getattr(instance, self.name + '_real')
        imag = getattr(instance, self.name + '_imag')
        return complex(real, imag)

    def __set__(self, instance, value: complex):
        setattr(instance, self.name + '_real', value.real)
        setattr(instance, self.name + '_imag', value.imag)


class Test(models.Model):
    num1 = ComplexField()
    num2 = ComplexField()
    num3 = ComplexField()


Миграция для этого выглядит как

migrations.CreateModel(
    name="Test",
    fields=[
        (
            "id",
            models.AutoField(
                auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
            ),
        ),
        ("num1_real", models.FloatField()),
        ("num1_imag", models.FloatField()),
        ("num2_real", models.FloatField()),
        ("num2_imag", models.FloatField()),
        ("num3_real", models.FloatField()),
        ("num3_imag", models.FloatField()),
    ],
)

так что, как вы видите, три ComplexField разбиты на шесть FloatField с.

...