2

Je le suivant défini dans mon modèle:Django ne pas en cascade supprimer objectale générique clé étrangère

class TaskLink(models.Model): 
    task = model.ForeignKey(Task) 
    link_choices = (
     models.Q(app_label="accounts", model="location"), 
     # Other models are also linked to here. 
    ) 
    linked_content_type = \ 
     models.ForeignKey(
      ContentType, 
      limit_choices_to=link_choices 
     ) 
    linked_object_id = models.PositiveIntegerField() 
    linked_object = \ 
     generic.GenericForeignKey(
      'linked_object_content_type', 
      'linked_object_id' 
     ) 

Ce modèle relie Task objets avec l'un des modèles du tuple link_choices. Dans ce cas, le modèle accounts.Location est dans cette liste.

Mon problème survient lorsque la suppression d'un objet Location entraîne la suppression en cascade des objets TaskLink associés. La suppression échoue avec le message d'erreur suivant:

django.core.exceptions.FieldError: Cannot resolve keyword 'object_id' into field. Choices are: id, linked_object, linked_object_content_type, linked_object_content_type_id, linked_object_id, task, task_id 

La vue est une instance de django.views.generic.DeleteView avec seulement le jeu de paramètres et le modèle pk_url_kwarg (décorateurs et des autorisations ajoutées à la méthode d'expédition); cela fonctionnait linked_object_fine avant d'ajouter le modèle TaskLink au mixage.

Qu'est-ce qui me manque?

EDIT: Il semble que cela puisse être un bug dans Django; lors de la suppression en cascade d'objets via des clés étrangères génériques, Django ignore les chaînes de noms de champs que vous passez au constructeur pour le champ GenericForeignKey et recherche plutôt les champs content_type et object_id qui, dans mon cas, n'existaient pas. Cela limite effectivement le nombre de clés étrangères génériques qu'un modèle peut avoir à 1, à moins que vous ne soyez pas en cours de suppression en cascade.

J'ai envoyé ce problème via la liste de diffusion Django car ce comportement peut être intentionnel.

Répondre

2

noms de champs de changement de nom de TaskLink

linked_content_type >>> content_type 
linked_object_id >>> object_id 

ou écrire le signal avant tout en supprimant "emplacement" objet à supprimer objet lié "TaskLink"

from django.db.models.signals import pre_delete 
from django.dispatch import receiver 

@receiver(pre_delete, sender=Location, dispatch_uid='location_delete_signal') 
def deleted_gfk_TaskLink(sender, instance, using, **kwargs): 
    ctype = ContentType.objects.get_for_model(sender) 
    obj = TaskLink.objects.get(linked_content_type=ctype, linked_object_id=instance.id) 
    obj.delete() 

de référence pour les signaux personnalisés:
https://micropyramid.com/blog/using-djangos-built-in-signals-and-writing-custom-signals/

+0

Marquer comme la réponse parce que cela résout le problème pour mon cas, mais je pense qu'il est important de noter: la façon dont Django h andles les clés étrangères génériques empêchent les modèles d'en avoir plus d'un si vous avez l'intention de dépendre de la cascade-delete. – Adam