2016-09-15 5 views
0

Джанго 1,10GenericForeignKey и on_delete = models.PROTECT

Скажем, у меня есть экземпляр рамы и два комментарии для него. Ключевой момент: on_delete = models.PROTECT в модели комментариев.

В оболочке:

Comment.objects.all() 
<QuerySet [<Comment: Some comment.>, <Comment: 
Second comment.>] 

Затем я удаляю экземпляр кадра (звоните FrameDelete). И:

Comment.objects.all() 
<QuerySet []> 

Пустой. Удалено все комментарии. И models.PROTECT не помогло.

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

class FrameDelete(IntegrityErrorMixin, DeleteView): 
    model = Frame 

class IntegrityErrorMixin(): 
    def delete(self, request, *args, **kwargs): 
     self.object = self.get_object() 
     success_url = self.get_success_url() 
     try: 
      self.object.delete() 
     except IntegrityError as err: 
      raise PermissionDenied 

     return HttpResponseRedirect(success_url) 

class Frame(models.Model): 
    ..... 
    comments = GenericRelation(Comment) 

class Comment(models.Model): 
    date = models.DateTimeField(null=False, 
          blank=False, 
          auto_now_add=True) 

    author = models.ForeignKey(User, on_delete=models.PROTECT) 
    body = models.TextField(blank=False, 
          null=False, 
          default="", 
          verbose_name = "",) # Empty. No need to show the verbose_name on the form. 

    content_type = models.ForeignKey(ContentType, on_delete=models.PROTECT) 
    object_id = models.PositiveIntegerField() 
    content_object = GenericForeignKey('content_type', 'object_id') 

ответ

4

Вы передаете on_delete=models.PROTECT на внешний ключ к ContentType. Это будет действовать только при удалении типа содержимого, а не при удалении комментария.

documentation states:

В отличие от ForeignKey, GenericForeignKey не принимает on_delete аргумент для настройки поведения; если это необходимо, вы можете избежать каскадного удаленияпросто, не используя GenericRelation, а альтернативное поведение может быть обеспечено через сигнал pre_delete.

Таким образом, чтобы имитировать поведение models.PROTECT, вам необходимо прикрепить pre_delete сигнал, который вызывает исключение, если существуют какие-либо связанные с ними комментарии, что-то вроде этого:

from django.db.models import ProtectedError, signals 

@receiver(signals.pre_delete, Frame) 
def protect_delete(sender, instance, **kwargs): 
    if instance.comments.exists(): 
     raise ProtectedError() 
Смежные вопросы