django模型继承:模型创建如何与Custom Manager一起使用?

时间:2019-11-13 18:58:10

标签: python django

最近,我遇到了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),但是为什么会这样呢?无法将手动创建的实例作为父级传递?我不允许在我的用例中使用继承吗?

1 个答案:

答案 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不起作用