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)
a source to share
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.
a source to share
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):
....
a source to share
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 signalpost_init
using a custom method and in that method, execute yourprocess()
andmake_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.
a source to share