Keyerror inside django model class __init__

Here's the Django class I wrote. This class gets a keyerror when I call get_object_or_404

from Django (I understand that keyerror is raised due to the lack of kwargs passed in the __init__

get function, the arguments are all positional). Interestingly, it doesn't get an error when I call get_object_or_404

from the console.

I wonder why, and if the code below is the correct way (i.e. using init to populate the link box) to create this class.

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)

      

+1


a source to share


4 answers


There is no reason to write your own classes __init__

for Django classes. I think you will be much happier.



Almost anything you think you want to do in __init__

can be done better in save

.

+2


a source


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

      

You are trying to retrieve an entry from a dictionary and then call its pop method. If you want to remove and return an object from the dictionary, call dict.pop()

:

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

      

Of course it won't work with KeyError

if "user"

not present in kwargs

. You want to provide a default value for pop:

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

      

This means that if it "user"

is in the dictionary, remove and return it. Otherwise, return None

".



As for the other two lines:

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

      

super().__init__()

will set link

on something, perhaps None

. I would cross out the lines, something like this:

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

      

You might want to add a test before setting the link to see if it exists ( if self.link is not None: ...

). This way the links you pass to the constructor will not be overwritten.

+7


a source


I don't think you need it __init__

here at all.

You always compute the reference value when you instantiate the class. This means that you are ignoring everything stored in the database. Since this is so, why bother with the modeling field at all? You would be better off binding the property to a getter using the code from _generate_link

.

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

      

+2


a source


ask a question why, and if the code below is correct (i.e. using __init__

links to populate the field) to build this class.

I got some problems when I tried to overload __init__

In maillist I got this answer

Better not to overload it with your own __init__

. Your best bet is to connect the signal post_init

using a custom method and in that method, execute your process()

and make_thumbnail()

.

In your case, the post_init signal should do the trick, and the implementation __init__

shouldn't be needed at all. You could write something like this:

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)

      

providing a keyword unique

for link = models.CharField(max_length=30, unique=True)

can also be helpful. If not specified, get_object_or_404 may not work if the same value in the reference field exists multiple times.

signals and unique in django-docs

+1


a source







All Articles