keyerror внутри класса модели django __init__ - PullRequest
1 голос
/ 15 мая 2009

Вот класс моделей Django, который я написал. Этот класс получает ключевую ошибку, когда я вызываю get_object_or_404 из Django (я предполагаю, что ключевая ошибка возникает из-за отсутствия kwargs, передаваемых в __init__ функцией get, все аргументы позиционные) Интересно, что я не получаю сообщение об ошибке, когда я вызываю 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 ]

7 голосов
/ 15 мая 2009
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: ...). Таким образом, ссылки, которые вы передаете в конструктор, не будут перезаписаны.

2 голосов
/ 15 мая 2009

Я не думаю, что вам нужен __init__ здесь вообще.

Вы всегда вычисляете значение ссылки, когда создается экземпляр класса. Это означает, что вы игнорируете все, что хранится в базе данных. Так как это так, зачем вообще беспокоиться о модельном поле? Лучше сделать ссылку на свойство, используя получатель с кодом _generate_link.

@property
def link(self): 
    ....
2 голосов
/ 15 мая 2009

Нет причин писать свои __init__ для классов моделей Django. Я думаю, что вы будете намного счастливее без этого.

Почти все, что, по вашему мнению, вы хотите сделать в __init__, лучше сделать в save.

1 голос
/ 15 мая 2009

задаюсь вопросом, почему, и если приведенный ниже код является правильным способом (т. Е. Используется __init__ для заполнения поля ссылки) для создания этого класса.

Однажды у меня возникли проблемы при попытке перегрузить __init__ В почтовом ящике я получил этот ответ

Лучше не перегружать его своим __init__. Лучший вариант - подключить сигнал post_init с помощью пользовательский метод и в этом методе сделать ваш process() и make_thumbnail() звонки.

В вашем случае post_init-signal должен справиться с задачей, и реализация __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

...