Вопрос по python – Рекурсивное удаление в Google App Engine

6

Я использую google app engine с django 1.0.2 (и django-helper) и удивляюсь, как люди делают рекурсивное удаление. Предположим, у вас есть модель, которая выглядит примерно так:

class Top(BaseModel):
    pass

class Bottom(BaseModel):
    daddy = db.ReferenceProperty(Top)

Теперь, когда я удаляю объект типа «сверху», я хочу, чтобы все связанные «снизу»; объекты, которые будут удалены.

Как и сейчас, когда я удаляю "Top" объект, «нижний»; объекты остаются, и затем я получаю данные, которые нигде не принадлежат. При доступе к хранилищу данных в представлении я получаю:

Caught an exception while rendering: ReferenceProperty failed to be resolved.

Конечно, я мог бы найти все объекты и удалить их, но поскольку моя реальная модель имеет глубину не менее 5 уровней, я надеюсь, что есть способ убедиться, что это может быть сделано автоматически.

Я нашел этостатья о том, как это работает с Java, и это, кажется, почти то, что я тоже хочу.

Кто-нибудь знает, как я могу получить такое поведение в Django?

Ваш Ответ

4   ответа
6

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

По соображениям производительности вы почти наверняка захотите использовать запросы только для ключей (позволяющие получить ключи сущностей, которые нужно удалить без необходимости извлекать и декодировать действительные сущности), а также пакетное удаление. Например:

db.delete(Bottom.all(keys_only=True).filter("daddy =", top).fetch(1000))
Wouldn & APOS; тdb.delete(top.bottom_set) работать просто отлично?
Из интереса, db.delete вызывает delete () для каждого объекта? Это чертовски оптимизировано, поэтому я немного подозреваю, что вы не можете объединить эти два трюка. Хороший вопрос о keys_only, хотя.
Я не могу заставить это работать, но этому ответу почти 4 года, так что это может быть так. GAE по-прежнему поддерживает запросы по ключам (решение jgeewax работало нормально)? Я искал, и это не ясно.
Да, это так - хотя db.delete (top.bottom_set.fetch (1000)) будет быстрее (при условии, что существует менее 1000 объектов).
Нет, db.delete () напрямую соответствует одному RPC, который отправляет все ключи, которые будут удалены параллельно. Entity.delete () - это просто синтаксический сахар, который вызывает db.delete (self).
2

На самом деле, это поведение специфично для GAE. ORM в Django имитирует "УДАЛИТЬ КАСКАД" на .delete ().

Я знаю, что это не ответ на ваш вопрос, но, возможно, это поможет вам смотреть не в том месте.

1

Если ваша иерархия имеет небольшое количество уровней, то вы можете сделать что-то с полем, которое выглядит как путь к файлу:

daddy.ancestry = "greatgranddaddy/granddaddy/daddy/"
me.ancestry = daddy.ancestry + me.uniquename + "/"

Такие вещи. Вам нужны уникальные имена, по крайней мере, уникальные среди братьев и сестер.

Путь в идентификаторах объектов своего рода уже делает это, но IIRC, который связан с группами объектов, которые вы рекомендуете не использовать для выражения отношений в области данных.

Затем вы можете создать запрос для возврата всех потомков дедушки, используя начальный трюк с подстрокой, например так:

query = Person.all()
query.filter("ancestry >", gdaddy.ancestry + "\U0001")
query.filter("ancestry <", gdaddy.ancestry + "\UFFFF")

Очевидно, что это бесполезно, если вы не можете вписать происхождение в 500-байтовое свойство StringProperty.

2

Пересмотреть структуру данных. Если отношение никогда не изменится в течение срока действия записи, вы можете использовать «предки». Особенность GAE:

class Top(db.Model): pass
class Middle(db.Model): pass
class Bottom(db.Model): pass

top = Top()
middles = [Middle(parent=top) for i in range(0,10)]
bottoms = [Bottom(parent=middle) for i in range(0,10) for middle in middles]

Затем запрос ancestor = top найдет все записи со всех уровней. Так что их будет легко удалить.

descendants = list(db.Query().ancestor(top))
# should return [top] + middles + bottoms
Красивая. Хорошее использование списка пониманий. Я впервые вижу одну петлю! Кажется, что они будут в другом порядке, с внешним циклом, идущим первым.

Похожие вопросы