Ошибка при наследовании абстрактного класса с внешними ключами - PullRequest
4 голосов
/ 19 декабря 2010

У меня есть приведенный ниже код, написанный на django

from django.db import models
from django.contrib.auth.models import User

class AuditColumns(models.Model):
    created_at=models.DateField("Created at")
    created_by=models.ForeignKey(User, db_column="created_by", related_name="poll_user_created_by")
    updated_at=models.DateTimeField("Updated at")
    updated_by=models.ForeignKey(User, db_column="updated_by", null=True, related_name="poll_user_updated_by")
    class Meta:
        abstract = True


class Poll(AuditColumns):
    question=models.CharField(max_length=300)
    start_poll_at=models.DateTimeField(null=True)
    end_poll_at=models.DateTimeField(null=True)
    is_active=models.BooleanField(default=True)


class Choice(AuditColumns):
    choice=models.CharField(max_length=200)

, когда я выполняю этот код, появляется следующая ошибка

mo@debian:~/PycharmProjects/KlamTam$ ./manage.py sql polls
Error: One or more models did not validate:
polls.poll: Accessor for field 'created_by' clashes with related field 'User.poll_user_created_by'. Add a related_name argument to the definition for 'created_by'.
polls.poll: Reverse query name for field 'created_by' clashes with related field 'User.poll_user_created_by'. Add a related_name argument to the definition for 'created_by'.
polls.poll: Accessor for field 'updated_by' clashes with related field 'User.poll_user_updated_by'. Add a related_name argument to the definition for 'updated_by'.
polls.poll: Reverse query name for field 'updated_by' clashes with related field 'User.poll_user_updated_by'. Add a related_name argument to the definition for 'updated_by'.
polls.choice: Accessor for field 'created_by' clashes with related field 'User.poll_user_created_by'. Add a related_name argument to the definition for 'created_by'.
polls.choice: Reverse query name for field 'created_by' clashes with related field 'User.poll_user_created_by'. Add a related_name argument to the definition for 'created_by'.
polls.choice: Accessor for field 'updated_by' clashes with related field 'User.poll_user_updated_by'. Add a related_name argument to the definition for 'updated_by'.
polls.choice: Reverse query name for field 'updated_by' clashes with related field 'User.poll_user_updated_by'. Add a related_name argument to the definition for 'updated_by'.

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

С уважением,

1 Ответ

8 голосов
/ 19 декабря 2010

Связанные имена предоставляются Django ORM, чтобы вы могли легко найти все модели, которые входят в текущую модель.Таким образом, если у вас есть ключ от Foo к Bar, экземпляр Bar по умолчанию будет иметь атрибут foo_set, который даст вам список всех Foo, связанных с этим конкретным Bar.

Вы можете указать свое собственное related_name, чтобы сделать ваш код более легким для чтения, с более естественными / подходящими related_names.

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

Хорошая новость: эта заметка в документации показываетОбходной путь для Django 1.2 +

Если по какой-то причине вам придется использовать Django 1.1 или более раннюю версию, вот альтернативный обходной путь: вместо использования FK на абстрактной модели, просто используйте поле длясохраните ПК для модели с ключами и добавьте соответствующие методы доступа.например:

class AuditBase(models.Model):
    created_at = models.DateTimeField("Created at", auto_now_add=True)
    created_by = models.IntegerField(required=True)
    updated_at = models.DateTimeField("Updated at", auto_now=True)
    updated_by = models.IntegerField(required=True)

    class Meta:
        abstract = True

@property
def creator(self):
    return User.objects.get(id=self.created_by) 

@property
def last_editor(self):
    return User.objects.get(id=self.updated_by)

def save(self, *args, **kwargs):
    #track the creator/last editor via an optional kwarg
    active_user = self.kwargs.get('user')
    if active_user:
       self.updated_by = active_user
    if active_user and not self.created_by:
       self.created_by = active_user

    return super(AuditBase, self).save(*args, **kwargs)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...