django模型类中的keyerror __init__

时间:2009-05-14 23:35:14

标签: python django django-models

这是我写的Django模型类。当我从Django调用get_object_or_404时,这个类得到了一个keyerror(我认为由于get函数没有将kwargs传递给__init__而引发了keyerror,所有参数都是位置的)。有趣的是,当我从控制台调用get_object_or_404时,它不会出错。

我想知道为什么,如果下面的代码是正确的方法(即使用 init 来填充链接字段)来构造这个类。

class Link(models.Model)

    event_type = models.IntegerField(choices=EVENT_TYPES)
    user = models.ForeignKey(User)
    created_on = models.DateTimeField(auto_now_add = True)
    link = models.CharField(max_length=30)
    isActive = models.BooleanField(default=True)

    def _generate_link(self):
        prelink = str(self.user.id)+str(self.event_type)+str(self.created_on)
        m = md5.new()
        m.update(prelink)
        return m.hexdigest()

    def __init__(self, *args, **kwargs):
        self.user = kwargs['user'].pop()
        self.event_type = kwargs['event_type'].pop()
        self.link = self._generate_link()
        super(Link,self).__init__(*args,**kwargs)

4 个答案:

答案 0 :(得分:7)

self.user = kwargs['user'].pop()
self.event_type = kwargs['event_type'].pop()

您正尝试从字典中检索条目,然后调用其pop方法。如果要从字典中删除并返回对象,请调用dict.pop()

self.user = kwargs.pop('user')

当然,如果KeyError中不存在"user",则kwargs会失败。您需要为pop提供默认值:

self.user = kwargs.pop('user', None)

这意味着“如果"user"在字典中,请删除并返回。否则,请返回None”。

关于其他两行:

self.link = self._generate_link()
super(Link,self).__init__(*args,**kwargs)

super().__init__()会将link设置为某个内容,可能是None。我会颠倒这些界限:

super(Link,self).__init__(*args,**kwargs)
self.link = self._generate_link()

您可能希望在设置链接之前添加测试,以查看它是否已存在(if self.link is not None: ...)。这样,您传递给构造函数的链接将不会被覆盖。

答案 1 :(得分:2)

没有理由为Django模型类编写自己的__init__。我想如果没有它我会更开心。

__init__中您认为想要做的事情几乎可以在save中完成。

答案 2 :(得分:2)

我认为你根本不需要__init__

在实例化类时,您总是在计算链接的值。这意味着您忽略数据库中存储的内容。既然如此,那么为什么还要打扰模型领域呢?最好使用_generate_link中的代码使用getter将链接作为属性。

@property
def link(self): 
    ....

答案 3 :(得分:1)

  

想知道为什么,如果下面的代码是正确的方法(即使用__init__来填充链接字段)来构造这个类。

我尝试重载__init__时遇到了一些问题 在maillist我得到了这个答案

  

最好不要用自己的重载   __init__。更好的选择是使用a挂钩post_init信号   自定义方法,并在该方法中执行您的process()和   make_thumbnail()来电。{/ p>

在你的情况下,post_init信号应该起作用,并且根本不需要实现__init__。 你可以这样写:

class Link(models.Model)
    event_type = models.IntegerField(choices=EVENT_TYPES)
    user = models.ForeignKey(User)
    created_on = models.DateTimeField(auto_now_add = True)
    link = models.CharField(max_length=30)
    isActive = models.BooleanField(default=True)

    def create_link(self):
        prelink = str(self.user.id)+str(self.event_type)+str(self.created_on)
        m = md5.new()
        m.update(prelink)
        return m.hexdigest()

def post_link_init(sender, **kwargs):
    kwargs['instance'].create_link()
post_init.connect(post_link_init, sender=Link)

>>> link = Link(event_type=1, user=aUser, created_on=datetime.now(), link='foo', isActive=True)

unique提供关键字link = models.CharField(max_length=30, unique=True)也可能有所帮助。如果未提供,则get_object_or_404可能无法在链接字段中的相同值存在多次的情况下起作用。

django-docs中的

signalsunique