Django - Model Inheritance - 상위 모델의 속성을 재정의할 수 있습니까?
이 작업을 수행할 예정입니다.
class Place(models.Model):
name = models.CharField(max_length=20)
rating = models.DecimalField()
class LongNamedRestaurant(Place): # Subclassing `Place`.
name = models.CharField(max_length=255) # Notice, I'm overriding `Place.name` to give it a longer length.
food_type = models.CharField(max_length=25)
이 버전은 제가 사용하고 싶은 버전입니다(어떤 제안에도 가능하지만). http://docs.djangoproject.com/en/dev/topics/db/models/ #id7
이것은 장고에서 지원됩니까?그렇지 않다면 비슷한 결과를 얻을 수 있는 방법이 있습니까?
업데이트된 답변: 사람들이 댓글에서 언급했듯이, 원래 답변은 질문에 제대로 대답하지 않았습니다.정말로, 오직.LongNamedRestaurant
모델이 데이터베이스에 생성되었습니다.Place
그렇지 않았습니다.
해결책은 "장소"를 나타내는 추상 모델을 만드는 것입니다.AbstractPlace
그리고 그것으로부터 물려받습니다.
class AbstractPlace(models.Model):
name = models.CharField(max_length=20)
rating = models.DecimalField()
class Meta:
abstract = True
class Place(AbstractPlace):
pass
class LongNamedRestaurant(AbstractPlace):
name = models.CharField(max_length=255)
food_type = models.CharField(max_length=25)
@Mark 답변도 읽어주세요, 그는 추상화되지 않은 클래스에서 상속된 속성을 변경할 수 없는 이유에 대해 훌륭한 설명을 해줍니다.
(Django 1.10: Django 1.10 이전에는 추상 클래스에서 상속된 속성을 수정할 수 없었기 때문에 가능합니다.)
원답
장고 1.10부터 가능합니다.당신은 당신이 요구한 것을 하기만 하면 됩니다.
class Place(models.Model): name = models.CharField(max_length=20) rating = models.DecimalField() class Meta: abstract = True class LongNamedRestaurant(Place): # Subclassing `Place`. name = models.CharField(max_length=255) # Notice, I'm overriding `Place.name` to give it a longer length. food_type = models.CharField(max_length=25)
아니요, 그렇지 않습니다.
필드 이름 "숨기기"는 허용되지 않습니다.
일반적인 Python 클래스 상속에서는 자식 클래스가 부모 클래스의 모든 속성을 재정의할 수 있습니다.장고에서는 다음과 같은 속성에 대해 허용되지 않습니다.
Field
인스턴스(적어도 현재는 아님).기본 클래스에 다음 필드가 있는 경우author
다음과 같은 다른 모델 필드를 만들 수 없습니다.author
해당 기본 클래스에서 상속되는 모든 클래스에서.
추상적이지 않으면 불가능하며, 그 이유는 다음과 같습니다.LongNamedRestaurant
또한Place
클래스뿐만 아니라 데이터베이스에도 있습니다.플레이스 테이블에는 모든 순수 항목이 포함되어 있습니다.Place
그리고 모두에게LongNamedRestaurant
.LongNamedRestaurant
그냥 추가 테이블을 만듭니다.food_type
플레이스 테이블에 대한 참조입니다.
네가 한다면.Place.objects.all()
당신은 또한 모든 장소를 얻을 수 있습니다.LongNamedRestaurant
그리고 그것은 의 사례가 될 것입니다.Place
(없이)food_type
. 그래서.Place.name
그리고.LongNamedRestaurant.name
동일한 데이터베이스 열을 공유하므로 같은 유형이어야 합니다.
저는 이것이 일반적인 모델들에게 타당하다고 생각합니다: 모든 식당은 장소이고, 적어도 그 장소가 가진 모든 것을 가져야 합니다.1.10 이전의 추상 모델에서는 이러한 일관성이 가능하지 않았지만 데이터베이스 문제는 발생하지 않았습니다.@lampslave 발언처럼 1.10에 가능했습니다.Sub.x가 Super.x를 재정의하는 경우 Sub.x가 Super.x의 하위 클래스인지 확인하십시오. 그렇지 않으면 Sub를 Super 대신 사용할 수 없습니다.
해결 방법:사용자 지정 사용자 모델을 생성할 수 있습니다.AUTH_USER_MODEL
전자 메일 필드만 변경하면 되는 경우 코드 중복이 상당히 많이 발생합니다.또는 전자 메일을 그대로 두고 모든 양식에 필요한 전자 메일인지 확인할 수 있습니다.이렇게 하면 다른 응용프로그램에서 데이터베이스를 사용할 경우 데이터베이스 무결성이 보장되지 않으며 사용자 이름을 사용할 필요가 없는 경우에도 데이터베이스 무결성이 보장되지 않습니다.
https://stackoverflow.com/a/6379556/15690 을 참조하십시오.
class BaseMessage(models.Model):
is_public = models.BooleanField(default=False)
# some more fields...
class Meta:
abstract = True
class Message(BaseMessage):
# some fields...
Message._meta.get_field('is_public').default = True
내 솔루션은 다음과 같이 간단합니다.monkey patching
내가 어떻게 변했는지 알아보세요.max_length
의 name
에 출전하다.LongNamedRestaurant
측정 결과:
class Place(models.Model):
name = models.CharField(max_length=20)
class LongNamedRestaurant(Place):
food_type = models.CharField(max_length=25)
Place._meta.get_field('name').max_length = 255
코드를 새 앱에 붙여넣고 앱을 설치_에 추가했습니다.APPS 및 실행 syncdb:
django.core.exceptions.FieldError: Local field 'name' in class 'LongNamedRestaurant' clashes with field of similar name from base class 'Place'
장고는 그것을 지원하지 않는 것 같습니다.
이 매우 멋진 코드 조각을 사용하면 추상 부모 클래스의 필드를 '재지정'할 수 있습니다.
def AbstractClassWithoutFieldsNamed(cls, *excl):
"""
Removes unwanted fields from abstract base classes.
Usage::
>>> from oscar.apps.address.abstract_models import AbstractBillingAddress
>>> from koe.meta import AbstractClassWithoutFieldsNamed as without
>>> class BillingAddress(without(AbstractBillingAddress, 'phone_number')):
... pass
"""
if cls._meta.abstract:
remove_fields = [f for f in cls._meta.local_fields if f.name in excl]
for f in remove_fields:
cls._meta.local_fields.remove(f)
return cls
else:
raise Exception("Not an abstract model")
필드가 추상 상위 클래스에서 제거되면 필요에 따라 필드를 다시 정의할 수 있습니다.
이것은 제 자신의 작품이 아닙니다.원본 코드: https://gist.github.com/specialunderwear/9d917ddacf3547b646ba
contribute_to_class:
class LongNamedRestaurant(Place):
food_type = models.CharField(max_length=25)
def __init__(self, *args, **kwargs):
super(LongNamedRestaurant, self).__init__(*args, **kwargs)
name = models.CharField(max_length=255)
name.contribute_to_class(self, 'name')
Syncdb는 잘 작동합니다.저는 이 예를 시도하지 않았습니다. 저의 경우 제약 조건 매개 변수를 재정의하기 때문에... 기다려 보십시오!
오래된 질문인 것은 알지만 비슷한 문제가 있었고 해결 방법을 찾았습니다.
저는 다음과 같은 수업을 들었습니다.
class CommonInfo(models.Model):
image = models.ImageField(blank=True, null=True, default="")
class Meta:
abstract = True
class Year(CommonInfo):
year = models.IntegerField()
하지만 저는 슈퍼클래스의 이미지 필드를 무효로 유지하면서 연도의 상속된 이미지 필드가 필요하기를 원했습니다.마지막으로 검증 단계에서 ModelForms를 사용하여 이미지를 적용했습니다.
class YearForm(ModelForm):
class Meta:
model = Year
def clean(self):
if not self.cleaned_data['image'] or len(self.cleaned_data['image'])==0:
raise ValidationError("Please provide an image.")
return self.cleaned_data
admin.py :
class YearAdmin(admin.ModelAdmin):
form = YearForm
이것은 일부 상황(특히 하위 클래스 필드에 더 엄격한 규칙을 적용해야 하는 경우)에만 적용되는 것 같습니다.
또다음사수있다니습용할을 할 수 있습니다.clean_<fieldname>()
대신 clean()
예를 들어 필드인 경우town
다음을 입력해야 합니다.
def clean_town(self):
town = self.cleaned_data["town"]
if not town or len(town) == 0:
raise forms.ValidationError("Please enter a town")
return town
모형 필드를 재정의할 수는 없지만 clean() 메서드를 재정의/지정하여 쉽게 실행할 수 있습니다.이메일 필드에 문제가 있어서 모델 레벨에서 고유하게 만들고 싶었고 다음과 같이 했습니다.
def clean(self):
"""
Make sure that email field is unique
"""
if MyUser.objects.filter(email=self.email):
raise ValidationError({'email': _('This email is already in use')})
그런 다음 "이메일"이라는 이름의 양식 필드에서 오류 메시지가 캡처됩니다.
언급URL : https://stackoverflow.com/questions/2344751/in-django-model-inheritance-does-it-allow-you-to-override-a-parent-models-a
'programing' 카테고리의 다른 글
코어 레벨 또는 ORM 레벨에서만 SQLAlchemy SQL 주입 보호 (0) | 2023.08.14 |
---|---|
Py.test 이름이 *인 모듈이 없습니다. (0) | 2023.08.14 |
$profile의 기본값을 새 값으로 변경할 수 있습니까? (0) | 2023.08.14 |
문자열의 줄 위에 반복합니다. (0) | 2023.08.14 |
PowerShell에서 애플리케이션 풀 ID 사용자 및 암호를 지정하는 방법 (0) | 2023.08.14 |