Джанго: AuditTrail & Lazy Relations - PullRequest
       7

Джанго: AuditTrail & Lazy Relations

1 голос
/ 26 августа 2009

Я пытался изменить код AuditTrail , чтобы он не копировал поля ForeignKey, а скорее копировал соответствующее поле (т. Е. Мне не нужен внешний ключ в моей таблице базы данных для модели аудита).

Я написал copy_field функцию, которая выглядит так:

def copy_field(field):
    while(isinstance(field, models.OneToOneField, models.ForeignKey)):
        field = field.rel.get_related_field()
    if isinstance(field, models.AutoField):
        f = models.IntegerField()
    else:
        f = copy(field)
    #...snip some adjusting of fs attributes...
    return f

Этот код запускается при подготовке модели с атрибутом AuditTrail (через сигнал class_prepared).

Однако, это сталкивается с проблемами, когда ForeignKey связан с полем в модели, которая еще не была подготовлена ​​- вызов get_related_field() не удастся, потому что field.rel.to - это строка, содержащая имя соответствующего модель, а не экземпляр модели.

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

1 Ответ

0 голосов
/ 02 сентября 2009

Я закончил тем, что перечислил все зависимости, которые имела модель (определив каноническую пару приложение / имя; скопировав некоторый код из django.db.models.fields.related, чтобы определить это) и изменив мой обработчик сигнала class_prepared, чтобы прослушать все модели, а не только моя целевая модель.

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

    dependencies = []
    for field in cls._meta.local_fields:
        while isinstance(field, (models.OneToOneField, models.ForeignKey)):
            if isinstance(field.rel.to,basestring):
                dependencies.append(get_canonical(cls,field.rel.to))
                break
            else:
                field = field.rel.get_related_field()

    def _contribute(sender, **kwargs):
        key = (sender._meta.app_label, sender.__name__)
        if key in dependencies:
            dependencies.remove(key)
        if not dependencies:
            models.signals.class_prepared.disconnect(_contribute)
            model = create_audit_model(cls)

    models.signals.class_prepared.connect(_contribute, weak=False)
...