Поле модели Django по умолчанию основано на другом поле в той же модели



у меня есть модель, которую я хотел бы содержать имя субъектов и их инициалы. (Данные несколько анонимизированы и отслеживаются по инициалам.)



прямо сейчас, я писал



class Subject(models.Model):

name = models.CharField("Name", max_length=30)
def subject_initials(self):
return ''.join(map(lambda x: '' if len(x)==0 else x[0],
self.name.split(' ')))
# Next line is what I want to do (or something equivalent), but doesn't work with
# NameError: name 'self' is not defined
subject_init = models.CharField("Subject Initials", max_length=5, default=self.subject_initials)


Как указано в последней строке, я бы предпочел, чтобы инициалы действительно сохранялись в базе данных как поле (независимо от имени), но это инициализируется значением по умолчанию на основе поля name. Тем не менее, у меня возникли проблемы, поскольку модели django не кажутся есть "я".



Если я изменю строку на subject_init = models.CharField("Subject initials", max_length=2, default=subject_initials), Я могу сделать syncdb, но не могу создавать новые предметы.



возможно ли это в django, когда вызываемая функция дает значение по умолчанию для некоторого поля на основе значения другого поля?



(для любопытных, причина, по которой я хочу отделить мои инициалы магазина отдельно, в редких случаях, когда странные фамилии могут отличаться от тех, которые я отслеживаю. Например, кто-то другой решил, что субъект 1 по имени " Джон Инициалы o'Mallory - это "JM", а не" JO", и он хочет исправить его как администратор.)

934   4  

4 ответов:

модели, конечно, есть "я"! Просто вы пытаетесь определить атрибут класса модели как зависящий от экземпляра модели; это невозможно, поскольку экземпляр не существует (и не может) существовать до того, как вы определите класс и его атрибуты.

чтобы получить желаемый эффект, переопределите метод save () класса model. Внесите необходимые изменения в экземпляр, а затем вызовите метод суперкласса, чтобы выполнить фактическое сохранение. Вот так быстро образец.

def save(self, *args, **kwargs):
    if not self.subject_init:
        self.subject_init = self.subject_initials()
    super(Subject, self).save(*args, **kwargs)

это описано в Переопределение Методов Модели в документации.

Я не знаю, если есть лучший способ сделать это, но вы можете используйте обработчик сигнала на the pre_save сигнал:

from django.db.models.signals import pre_save

def default_subject(sender, instance, using):
    if not instance.subject_init:
        instance.subject_init = instance.subject_initials()

pre_save.connect(default_subject, sender=Subject)

используя сигналов Django, это можно сделать довольно рано, получив the post_init сигнал из модели.

from django.db import models
import django.dispatch

class LoremIpsum(models.Model):
    name = models.CharField(
        "Name",
        max_length=30,
    )
    subject_initials = models.CharField(
        "Subject Initials",
        max_length=5,
    )

@django.dispatch.receiver(models.signals.post_init, sender=LoremIpsum)
def set_default_loremipsum_initials(sender, instance, *args, **kwargs):
    """
    Set the default value for `subject_initials` on the `instance`.

    :param sender: The `LoremIpsum` class that sent the signal.
    :param instance: The `LoremIpsum` instance that is being
        initialised.
    :return: None.
    """
    if not instance.subject_initials:
        instance.subject_initials = "".join(map(
                (lambda x: x[0] if x else ""),
                instance.name.split(" ")))

The post_init сигнал отправляется классом после того, как он сделал инициализацию на экземпляре. Таким образом, экземпляр получает значение для name перед проверкой, установлены ли его ненулевые поля.

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

from django.db.models.signals import pre_save
from django.dispatch import receiver


@receiver(pre_save, sender=Subject)
def default_subject(sender, instance, **kwargs):
    if not instance.subject_init:
        instance.subject_init = instance.subject_initials()

эта функция приемника также принимает **kwargs подстановочные аргументы ключевых слов, которые все обработчики сигналов должны принимать в соответствии с https://docs.djangoproject.com/en/2.0/topics/signals/#receiver-functions.

Comments

    Ничего не найдено.