2011-08-03 1 views
1

나는 그 자체와 다 대다 관계를 가진 모델을 가지고있다.django 모델의 루프 감지

그룹이 자신의 하위 그룹 또는 하위 그룹의 하위 그룹 등이되지 못하게하는 모델에 대한 유효성 검사를 만들고 싶습니다. 그 목적은 루프/무한 재귀.

다음과 같이 model clean() 메서드에서 구현하려고 시도했습니다.

또한 트랜잭션을 사용하여 save() 모델 모델에서이 구현을 시도했습니다.

두 경우 모두 유효하지 않은 변경 사항이 (잘못) 데이터베이스에 저장되는 상황이 발생했으나 두 인스턴스 중 하나를 추가로 변경하려고하면 유효성 검사에서 오류를 감지하지만 그 시점에서 , 잘못된 데이터가 이미 데이터베이스에 있습니다.

이것이 가능한지 궁금한 데요, 그렇다면 모델 유효성 검사에서 가능하면 내 팀의 모든 사람들이 작성한 모든 양식에서이 유효성 검사를 호출하는 것을 기억하지 않아도됩니다. 미래. 지체없이

코드 :

class Group(models.Model): 
    name = models.CharField(max_length=200) 
    sub_groups = models.ManyToManyField('self', through='SubGroup', symmetrical=False) 

    def validate_no_group_loops(self, seen=None): 
     if seen is None: 
      seen = [] 
     if self.id in seen: 
      raise ValidationError("LOOP DETECTED") 
     seen.append(self.id) 
     for sub_group in self.target.all(): 
      sub_group.target.validate_no_group_loops(seen) 

    # I thought I would use the standard validation mechanism in the clean() 
    # method, but it appears that when I recurse back to the group I started 
    # with, I do so with a query to the database which retreives the data before 
    # it's been modified. I'm still not 100% sure if this is the case, but 
    # regardless, it does not work. 
    def clean(self): 
     self.validate_no_group_loops() 

    # Suspecting that the problem with implementing this in clean() was that 
    # I wasn't testing the data with the pending modifications due to the 
    # repeated queries to the database, I thought that I could handle the 
    # validation in save(), let the save actually put the bad data into the 
    # database, and then roll back the transaction if I detect a problem. 
    # This also doesn't work. 
    def save(self, *args, **kwargs): 
     super(Group, self).save(*args, **kwargs) 
     try: 
      self.validate_no_group_loops() 
     except ValidationError as e: 
      transaction.rollback() 
      raise e 
     else: 
      transaction.commit() 


class SubGroup(models.Model): 
    VERBS = { '+': '+', '-': '-' } 
    action = models.CharField(max_length=1, choices=VERBS.items(), default='+') 
    source = models.ForeignKey('Group', related_name='target') 
    target = models.ForeignKey('Group', related_name='source') 

감사에 앞서 당신이 제공 할 수있는 지원 시간.

[편집] FYI, 트랜잭션 관리에 사용하는 메커니즘을 기반으로 말할 수 없다면 현재 RHEL6 용 페도라 EPEL 저장소에서 사용할 수있는 장황한 1.2를 사용하고 있습니다. 솔루션을 사용할 수 있지만 1.3으로 업그레이드해야하는 경우 업그레이드해도 문제가 없습니다. 또한 Red Hat에서 RHEL6에서 사용할 수있는 Python 2.6.6을 사용하고 있습니다. 차라리 파이썬 업그레이드를 피하고 싶지만 관련성이 높은지 의심 스럽다.

+0

왜 다 대다 관계를 사용하는지 설명해 주실 수 있습니까? 구조와 같은 트리가 있고이 패턴을 사용합니다.이 노드가 비어 있으면 모든 노드에 "부모"특성이 있습니다. 루트 노드입니다. 또는 https://github.com/django-mptt/django-mptt/ – guettli

+0

을 사용할 수 있습니다. 내 응용 프로그램에서는 나무가 아닙니다. 그룹이 다른 많은 그룹에 포함될 수도 있고, 그룹이 여러 그룹을 포함 할 수도 있습니다. 이것은 관련없는 코드가 많은 사람들에게 부담을주지 않으면 서 문제를 표현하는 응용 프로그램의 간소화 된 버전이기 때문에 하위 그룹 관계에 대한 매개 변수를 정의하기위한 통과 모델이 필요합니다. – mkomitee

+1

[내 질문] (http://stackoverflow.com/questions/5795742/django-mptt)에 링크 된 [django_dag] (https://github.com/elpaso/django-dag) 프로젝트를 보면 - 그리고 - parents-parents), models.py 라인 195에는'circular_checker'라는 이름의'@ staticmethod'가 있음을 알 수 있습니다. 코드에서 영감을 얻을 수 있습니다. –

답변

0

"대상 지정" 코드에서이 루프 안에 실제로 있습니까? 그것은 그것이 수준을 건너 뛰게하는 것처럼 보입니다.

for sub_group in self.target.all(): 
     sub_group.target.validate_no_group_loops(seen)