编写__init__函数以在Django模型中使用


73

我正在尝试为__init__我的一个模型编写函数,以便可以通过执行以下操作创建对象:

p = User('name','email')

当我编写模型时,我有:

def __init__(self, name, email, house_id, password):
    models.Model.__init__(self)
    self.name = name
    self.email = email

这样可以正常工作,我可以将对象保存到数据库中,但是当我这样做时User.objects.all(),除非我拿出__init__函数,否则它不会拉任何东西。有任何想法吗?


2
你为什么做这个?无需编写任何代码,该功能便是Django模型的一部分。
S.Lott

1
当我尝试不使用init时,由于某种原因,它们都会进入错误的字段,除非我指定了User(name ='aoeu'),这会占用很多额外的空间。
胜利者

6
显式字段=值分配有什么问题?从长远来看,您可能会更快乐。毕竟,您只编写了很少一部分这类代码。
S.Lott

Answers:


111

依靠Django的内置功能并传递命名参数将是最简单的方法。

p = User(name="Fred", email="fred@example.com")

但是,如果您打算保存一些击键,我建议您向类添加一个静态便捷方法,而不要弄乱初始化程序。

# In User class declaration
@classmethod
def create(cls, name, email):
  return cls(name=name, email=email)

# Use it
p = User.create("Fred", "fred@example.com")

2
是的,工厂方法是解决问题的方法。您也可以考虑将其放在Manager上。弄乱构造函数签名肯定会破坏事情。
卡尔·迈耶

4
@classmethod在create上也更好
aehlke

47

Django期望模型的构造函数的签名为(self, *args, **kwargs),或某种合理的传真。您将签名更改为完全不兼容的签名已将其破坏。


4
从Django 2.1开始,Ignacio的答案是正确的,应该接受。直接从2.1文档开始,他们说You may be tempted to customize the model by overriding the __init__ method. If you do so, however, take care not to change the calling signature as any change may prevent the model instance from being saved.docs.djangoproject.com/en/2.1/ref/models/instances
MikeyE

上述评论的链接还将提供有关如何以不同方式进行您想做的事情的建议。__init__从今天下午的经验中学到,重载可能导致各种奇怪的错误。
希尔克·瓦林加

19

正确的答案是避免重写__init__并按照Django文档中的描述编写类方法

但这可以像您正在尝试的那样完成,只需添加*args, **kwargs即可被您的接受__init__,然后将它们传递给super方法调用。

def __init__(self, name, email, house_id, password, *args, **kwargs):
        super(models.Model, self).__init__(self, *args, **kwargs)
        self.name = name
        self.email = email

7
super(models.Model,self).__ init __(* args,** kwargs)
alexcasalboni

2
super(<YourModelName>, self).__init__(*args, **kwargs)
Vadym Pasko,

2

不要使用args参数创建模型。如果您像这样制作模型:

 User('name','email')

由于大多数模型需要的初始化更多,因此变得非常难以理解。您可能很容易得出以下结论:

User('Bert', 'Reynolds', 'me@bertreynolds.com','0123456789','5432106789',....)

这里的另一个问题是您不知道'Bert'是名字还是姓氏。最后两个数字很容易就是电话号码和系统ID。但是,如果没有明确说明,您将更容易将它们混合在一起,或者如果您使用标识符,则可以将订单混合在一起。更重要的是,基于顺序执行此操作将给其他使用此方法并且不会记住参数的任意顺序的开发人员带来另一个限制。

您应该更喜欢这样的事情:

User(
    first_name='Bert',
    last_name='Reynolds',
    email='me@bertreynolds.com',
    phone='0123456789',
    system_id='5432106789',
)

如果这是用于测试或类似的东西,则可以使用工厂快速创建模型。工厂男孩链接可能有用:http : //factoryboy.readthedocs.org/en/latest/

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.