Django模型继承:如何使用自定义管理器创建模型?

2024-09-30 04:36:01 发布

您现在位置:Python中文网/ 问答频道 /正文

最近我遇到了一个关于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()

所以问题是:如何在我的PartyInviteManagercreate方法中传递已经存在的基类实例?即使使用方法1,我传递的现有的实例似乎也会被覆盖。将使用默认值创建一个新的。有趣的是,这违反了code不能为空或NULL的限制。你知道吗

我觉得这种行为有点奇怪?有人能指出我遗漏了什么吗?你知道吗

澄清一下:我知道我通常应该在create方法中使用**kwargs,继承可能不是这里理想的用例,但我只是对这种行为非常好奇。 我知道这种模型继承甚至不会为子模型创建pk(因为将OneToOneField保存到父类实际上充当了pk),但是为什么不可能将手动创建的实例作为父类传递呢?我不允许在我的用例中使用继承吗?你知道吗


Tags: the实例模型falsereturnismodelscreate
1条回答
网友
1楼 · 发布于 2024-09-30 04:36:01

我想我找到了正确的方法:

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继承,那么InviteBaseManagercreate方法在创建新的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)

生成以下输出:

ABCD
ABCD

PartyInviteManagercreate方法中,可以直接使用code=XXXXInviteBase模型传递字符串,另一方面invite_code不起作用。你知道吗

相关问题 更多 >

    热门问题