Django: ошибка "ZeroToOneField" DoesNotExist - PullRequest
1 голос
/ 27 июля 2011

Я пытаюсь определить наилучший способ установления отношения «ноль к одному» между двумя моделями.Например, модель с именем Post может иметь ноль или один связанный экземпляр модели с именем PostExtra.Я бы хотел, чтобы все было наоборот.

from django.db import models

class PostExtra(models.Model):

    author = models.CharField(max_length=64)
    active = models.BooleanField(default=False)  

    """
    Assigned a property to prevent DoesNotExist error when calling 
    self.post, but property does not override self.post properly 
    for some reason. 
    """ 
    def _get_post(self):
        return_value=None
        try:
            return_value = self.post
        except:
            pass
        return return_value

    def _set_post(self, post):
        self.post = post

    post = property(_get_post, _set_post)

    def __unicode__(self):
        return "%s" % (self.author)

class Post(models.Model):

    title = models.CharField(max_length=64)
    text = models.TextField()
    extra = models.OneToOneField('a.PostExtra', blank=True, null=True)

    def __unicode__(self):
        return "%s" % (self.title)

Здесь я могу создать Post ()

>>> p = Post(title="test 1", text="test text")
>>> p.save()
>>> p.extra    # this returns None as it should

Как указано выше, поскольку я сделал Post.extra OneToOneField с пустым = True / null = True, p.extraвернет Null, если PostExtra не назначен.Однако, если я делаю обратное и пытаюсь получить доступ к PostExtra.post, я получаю ошибку DoesNotExist.

>>> pe = PostExtra(author='John Doe')
>>> pe.save()
>>> pe.post 
...
DoesNotExist: Post matching query does not exist.

Я попытался назначить свойство в PostExtra, чтобы переопределить PostExtra.post, используя свойство, но я все еще получаю ошибку.Кто-нибудь нашел способ заставить OneToOneFields не генерировать исключение (и возвращать Null) при попытке доступа к несуществующему связанному элементу?

Любой совет очень ценится.

1 Ответ

3 голосов
/ 27 июля 2011

Вам нужно указать другой related_name в ваших отношениях , чтобы этот тип кода работал.

from django.core.exceptions import ObjectDoesNotExist
class PostExtra(models.Model):
    pass ## Brevity.
    def _get_post(self):
        return_value=None
        try:
            return_value = self._post
        except ObjectDoesNotExist: ## Be explicit if you can.
            pass
        return return_value
    def _set_post(self, post):
        self._post = post
    post = property(_get_post, _set_post)

class Post(models.Model):
    pass ## Brevity.
    extra = models.OneToOneField('a.PostExtra', blank=True,
                      null=True, related_name='_post')

После этого вы можете получить доступ к записи в несколькихпо-разному:

>>> pe = PostExtra(author='John Doe')
>>> pe.save()
>>> pe.post
None
>>> pe._post
DoesNotExist: Post matching query does not exist.

Ниндзя Править:
Может возникнуть вопрос: «Почему я должен делать это так?».Ответ заключается в том, что когда классы модели Django устанавливают ваш объект PostExtra, он создает PostExtra.post в качестве ссылки обратно на Post.Я не знаком с самим кодом, но сомневаюсь, что он проверяет, свободен ли берег перед выполнением назначения, так как программист сказал ему установить такое отношение.В результате вы должны указать неконфликтующее свойство для используемых модельных классов Django, таким образом, аргумент related_name.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...