Как хранить комплексное число в модели 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)

2
задан Brian 19 March 2019 в 13:46
поделиться

3 ответа

Если ваше выражение каждый раз напоминает 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
ответ дан Tobit 19 March 2019 в 13:46
поделиться

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

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

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

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

0
ответ дан Endre Both 19 March 2019 в 13:46
поделиться

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

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

  • contribute_to_class называется глубоко в механизме модели Джанго для всех полей, которые объявлены в модели. Как правило, они могут просто добавить само поле в модель и, возможно, дополнительные методы, такие как get_latest_by_..., но здесь мы угоняем этот механизм, чтобы вместо этого добавить два поля, в которых мы строим, а не само поле «себя» вообще , поскольку он не должен существовать как столбец базы данных. (Это может что-то сломать, кто знает ...) Часть этого механизма объясняется здесь в вики Django.

  • Класс ComplexProperty является дескриптором свойства , который позволяет настраивать то, что происходит, когда свойство, к которому он «присоединен», обращается к экземпляру (осуществляется чтение или запись). (То, как работают дескрипторы, немного выходит за рамки этого ответа, но в документации по Python есть руководство .)

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 с. [1119 ]

0
ответ дан AKX 19 March 2019 в 13:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: