Development Tip

Django 모델 필드 기본값은 동일한 모델의 다른 필드를 기반으로 함

yourdevel 2020. 10. 12. 08:16
반응형

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)

마지막 줄에서 알 수 있듯이 이니셜은 실제로 데이터베이스에 필드 (이름과 무관)로 저장되는 것을 선호하지만 이름 필드를 기반으로하는 기본값으로 초기화됩니다. 그러나 django 모델에 '자신'이없는 것 같아 문제가 있습니다.

줄을으로 변경하면 subject_init = models.CharField("Subject initials", max_length=2, default=subject_initials)syncdb를 수행 할 수 있지만 새 주제를 만들 수는 없습니다.

호출 가능한 함수가 다른 필드의 값을 기반으로 일부 필드에 기본값을 제공하도록 장고에서 가능합니까?

(궁금한 점은 매장 이니셜을 따로 분리하고 싶은 이유는 드물게 이상한 성이 내가 추적하는 것과 다를 수 있기 때문입니다. "JO"가 아닌 "JM"을 수정하고 관리자 권한으로 수정하려고합니다.)


모델에는 확실히 "자아"가 있습니다! 모델 인스턴스에 의존하는 것으로 모델 클래스의 속성을 정의하려는 것입니다. 클래스와 속성을 정의하기 전에 인스턴스가 존재하지 않기 때문에 불가능합니다.

원하는 효과를 얻으려면 모델 클래스의 save () 메서드를 재정의하십시오. 필요한 인스턴스를 원하는대로 변경 한 다음 슈퍼 클래스의 메서드를 호출하여 실제 저장을 수행합니다. 다음은 간단한 예입니다.

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

이것은 문서의 모델 메서드 재정의 에서 다룹니다 .


이 일을 더 나은 방법이 있는지 모르겠지만, 당신은 할 수 신호 처리기를 사용 하기위한 신호 :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 신호를 사용 하면 모델 에서 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(" ")))

post_init이 인스턴스에 초기화 완료되면 신호는 클래스에 의해 전송됩니다. 이런 식으로 인스턴스는 namenullable이 아닌 필드가 설정되었는지 테스트하기 전에 값을 가져옵니다 .


Gabi Purcaru 답변 의 대안 구현으로 데코레이터를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()

This receiver function also takes the **kwargs wildcard keyword arguments which all signal handlers must take according to https://docs.djangoproject.com/en/2.0/topics/signals/#receiver-functions.

참고URL : https://stackoverflow.com/questions/4380879/django-model-field-default-based-off-another-field-in-same-model

반응형