最近,我遇到了Django问题,模型继承问题以及模型实例的创建方式。 假设我具有以下(基本)设置:
class InviteBaseManager(models.Manager):
def create(self):
new_code = # create some kind of unique code, not really relevant here.
return super().create(code=new_code)
class InviteBase(models.Model):
code = models.CharField(max_length=10, blank=False, null=False, unique=True)
creationDate = models.DateTimeField(default=timezone.now())
objects = InviteBaseManager()
class PartyInviteManager(models.Manager):
def create(self, name):
# method 1
newInvite = InviteBase.objects.create()
print(newInvite.code) # is definitly set, lets assume "ABCD"
# as expexted, the "InviteBase" table has one row with code "ABCD" and
# default creationDate
newPartyInvite = super().create(partyName=name, invite=newInvite)
print(newPartyInvite.invite.code) # is EMPTY, prints nothing
# In fact, when looking at the db, there is still only *one* row in the table "InviteBase",
# with an *empty* code field and a default creationDate field.
return newPartyInvite
#method 2
newPartyInvite = super().create(partyName=name)
# creates the InviteBase instance implicitly, again, newPartyInvite.invite.code is empty.
# fill newPartyInvite.invity.code manually.
return newPartyInvite
class PartyInvite(InviteBase):
#Isn't blank=False and null=False unnecessary? A child should probably not exist with no parent?
invite = models.OneToOneField(InviteBase, parent_link=True, on_delete=models.CASCADE, null=False, blank=False)
partyName = models.CharField(...)
objects = PartyInviteManager()
所以问题是:如何在create
的{{1}}方法内传递基类的现有实例?即使使用方法1,我传递的 existing 实例也似乎被覆盖。将使用默认值创建一个新值。有趣的是,这违反了PartyInviteManager
不能为空或code
的约束。
这种行为对我来说似乎有点奇怪?有人可以指出我在这里想念的东西吗?
为了阐明这一点:我知道我通常应该在NULL
方法中使用**kwargs
,并且继承在这里可能不是理想的用例,但是我对此行为非常好奇。
我知道,这种模型继承甚至不会为子模型创建create
(因为将pk
保留给父类实际上还是充当OneToOneField
),但是为什么会这样呢?无法将手动创建的实例作为父级传递?我不允许在我的用例中使用继承吗?
答案 0 :(得分:0)
我认为我已经找到正确的方法:
factory(App\HostelReview::class, 10)->create(['hostel_id' => 30]);
class InviteBaseManager(models.Manager):
def create(self, **kwargs):
kwargs['code'] = #createCode
return super().create(**kwargs)
class InviteBase(models.Model):
code = models.CharField(max_length=10, blank=False, null=False, unique=True)
creationDate = models.DateTimeField(default=timezone.now())
objects = InviteBaseManager()
class PartyInviteManager(InviteBaseManager):
def create(self, name):
return = super().create(partyName=name)
class PartyInvite(InviteBase):
invite = models.OneToOneField(InviteBase, parent_link=True, on_delete=models.CASCADE, null=False, blank=False)
partyName = models.CharField(...)
objects = PartyInviteManager()
现在也从PartyInviteManager
继承了。从子管理器调用InviteManager
时,将调用基本管理器,并附加super.create()
字段,一切都会按预期进行。
我还发现,如果code
不从PartyInviteManager
继承而来,则创建时不会调用InviteBaseManager
的{{1}}方法新的create
。对我来说这很奇怪。
当然,更简单的方法是通过如下函数将代码创建为默认值:
InviteBaseManager
但是,如果根据子类的不同,代码需要其他信息(例如受邀成员等),则此方法将不再起作用。
有趣的是,下面的代码片段很有趣:
PartyInvite
产生以下输出:
def createCode():
return "ABCD" # add fancy code creation magic here.
class InviteBase:
code = models.CharField(max_length=128, blank=False, null=False, default=createCode)
在invite = PartyInviteManager.objects.create(partyName='Birthday')
print(invite.invite.code)
print(invite.code)
的{{1}}方法中,一个人可以直接使用ABCD
ABCD
传递create
模型的字符串,而另一个传递PartyInviteManager
手不起作用。