Django: Создание модели на основе разбора поля другой модели

У меня есть модель A с несколькими полями. Одно из полей ("results") является диктоподобной строкой в моей базе данных (которая едва ли читаема для человека). Могу ли я создать отдельную модель, которая будет разбирать это поле "результаты" на свои собственные поля, чтобы у меня была отдельная таблица с полями, соответствующими ключам и значениям поля "результаты" из модели A? Конечная цель - сделать таблицу результатов, которая показывает всю информацию в красивой и легко читаемой форме.

class ModelA(models.Model):
    language = models.CharField(max_length=30)
    date = models.DateTimeField()
    results = models.CharField(max_length=255)

Вот как поле "результаты" выглядит в моей базе данных (я не могу изменить этот формат):

OrderedDict([('Name', 'Bob'), ('Phone', '1234567890'), ('born', '01.01.1990')]))

Я хочу создать что-то вроде этого:

class Results(models.Model):
    name = model.Charfield(max_length=100)
    phone= model.IntegerField()
    born = model.DateTimeField()

Каким образом лучше всего это сделать? Как мне взять информацию из поля "результаты" из моделиА и "поместить" ее в модель Results?

Вы можете сделать функцию, которая преобразует его обратно в словарь с помощью:

from ast import literal_eval
from datetime import datetime

def results_process(text):
    if not (text.startswith('OrderedDict(') and text.endswith(')')):
        raise ValueError('Invalid format')
    data = dict(literal_eval(text[12:-1]))
    return Results.objects.create(
        name=data['Name'],
        phone=data['Phone'],
        born=datetime.strptime(data['born'], '%d.%m.%Y')
    )

для заданной строки, содержащейся в results объекте ModelA, он таким образом построит Results объект модели, хранящийся в базе данных.

Вы можете создать свойства модели, которые заставят пары ключ:значение в этой дикте выглядеть так, как будто это обычные поля модели для многих целей кодирования (но не querysets или ModelForms)

Вообще-то я бы очень очень хотел изменить результаты на JSON-поле, но я предположу, что вы не используете PostgreSQL ...

class ModelA(models.Model):
    results = models.CharField(max_length=255)

    @property
    def  name(self):
        if not hasattr(self, _rdict):
            self._parse_results()
        return self._rdict['name']
    @name.setter
    def name( self, value):
        if not hasattr(self, _rdict):
            self._parse_results()
        self._rdict['name'] = value

    # similarly for the other keys in results
    # if thre are lots of keys, to be DRY investigate the property builtin
    # field = property( getter, setter)

    def _parse_results(self):
        d = OrderedDict() 
        # use self.results to turn results back into an OrderedDict
        # code (use python re module? ) tbs
        # set d['name'] = parsed_name  etc in the right order!

        self._rdict = d

    def save( self, *args, **kwargs):
        # rewrite results to reflect _rdict contents
        # this is a hack implementation 
        # (but I suspect it's how results is generated)

        self.results = str( self._rdict)
        super().save(*args, **kwargs)

Вы могли бы сэкономить все эти hasattr тесты, если бы вместо этого декодировали результаты в __init__ модели после вызова super().__init__. Я не знаю почему, но Django doc предостерегает от этого (или раньше предостерегал). Я сделал это с одной из своих моделей, и пока что никаких плохих последствий я не заметил. Вмешательство до того, как суперкласс сделает свою магию, может быть тем, от чего он предостерегает. Сейчас я не могу найти это предупреждение.

Если вы хотите использовать (скажем) модельформ, основанный на "полях" в результатах. есть другой способ, который может помочь: наследование по нескольким таблицам. Я не знаю достаточно, чтобы рекомендовать это. Он создает автоматическое отношение OneToOne между текущей таблицей DB и вашей новой моделью. Затем вам придется подклассифицировать метод __init__ вашей модели, чтобы расшифровать результаты. Удачи, если вы попытаетесь сделать это (и если у вас получится, опубликуйте то, что вы сделали, здесь в качестве ответа на свой вопрос, потому что я хотел бы знать! )

Я бы сказал связать две модели с foreignKey, чтобы получить доступ к ним как к словарю в вашем представлении. Свяжите так:

class ModelA(models.Model):
    language = models.CharField(max_length=30)
    date = models.DateTimeField()
    results = models.CharField(max_length=255)

class Results(models.Model):
    # Here we are creating a relationship between the two model
    # so that we can get their data by related names.
    model_a = models.ForeignKey(MadelA,on_delete=models.CASCADE)
    name = model.Charfield(max_length=100)
    phone= model.IntegerField()
    born = model.DateTimeField()

В нашем представлении мы можем получить данные для обеих моделей, используя их связанное имя, так как django предоставляет связанное имя по умолчанию, если оно не предоставлено, как в моем решении, поэтому связанное имя для двух моделей будет results_set, которое будет использоваться для получения данных для обеих моделей в нашем представлении, будь то словарь, список или кортеж, когда мы запрашиваем данные из бэкенда.


getting both data by related name

ModelA.objects.prefetch_related('results_set').dict()



Вернуться на верх