2013-07-02 4 views
0

이것은 stackoverflow에 대한 첫 번째 게시물이므로 질문하는 방법에 대한 비판을 환영합니다. 내 코드에서Django - get_or_create 트리거 RunTimeError : 최대 재귀 깊이 초과

, 나는이 오류가 :

여기
RuntimeError: maximum recursion depth exceeded 

코드입니다 (내용이 무관하다, 난 그냥 간단한 방법 할 수있는 오류를 재현). 기본적으로 __init__를 재정의하려고합니다. 개체가 데이터베이스에 있으면 무언가를하고 싶지 않으면 무언가를하고 싶습니다.

Question('how are you?') 

나는 문제가 get_or_create 방법에서 유래 이해 : 생성자를 호출 할 때

class Question(models.Model): 

    text = models.CharField(max_length=140) 
    asked = models.BooleanField(default=False) 

    def __init__(self, text, *args): 
     #called the __init__ of the superclass. 
     super(Question, self).__init__() 

     self, c = Question.objects.get_or_create(text=text) 
     if c: 
      print 'This question will be asked!' 
      self.asked = True 
      self.save() 
     else: 
      print 'This question was already asked' 
      assert self.asked == True 

오류가 발생합니다.

---> 12   self, c = Question.objects.get_or_create(text=text) 
... 
---> 146   return self.get_query_set().get_or_create(**kwargs) 
... 
---> 464     obj = self.model(**params) 

get_or_create 어떤 시점에서 객체의 생성자를 호출, 오류 메시지에서 찾고있다. 어떤은 ... get_or_create 다시 등 호출

편집 :

Question('How are you?') 

를하고 데이터베이스에, 또는 새로 만든 경우 개체가 반환 갖는 기본적으로 내가 쓸 수있게되고 달성하고 싶은 무엇 그렇지 않은 경우 하나를 저장합니다. 대신 같은의 :

> try: 
>  q = Question.objects.get(text='How are you?') 
> except Question.DoesNotExist: 
>  q = Question(text='How are you?') 
>  q.save() 

그래서 나는 이것을 달성하는 유일한 방법은 __init__를 재정 의하여이라고 생각한다. 그것은 가능하지 않거나 개념적으로 틀린가 (또는 둘 다)? 감사!

+1

난 당신이 __init__ 방법 : – lalo

+0

당신이'자기, C = Question.objects.get_or_create (텍스트 = 텍스트)'와 함께 일을하려고 무엇을 덮어 쓰지해야한다고 생각? – lalo

+0

방금 ​​내 목표를 더 이해하기 쉽게 편집했습니다. – forbo

답변

2

당신은 정말 시도하고 __init__이를해서는 안된다. (사실, Django 모델의 __init__ 만 남겨 두는 것이 가장 좋습니다.) 폼 또는보기로 이동해야합니다.

어쨌든 self에 할당하여 인스턴스 자체를 덮어 쓸 수 없습니다. 다른 인스턴스처럼 로컬 변수 일 뿐이며 메서드의 끝 부분에서 범위를 벗어납니다.

또한 기존 찾을 수없는 경우 새 인스턴스에 설정되는 기본 값을 전달 get_or_createdefaults 매개 변수를 사용할 수 있습니다 :

question, created = Question.objects.get_or_create(text=text, defaults={'asked': True}) 

편집 질문 업데이트 후 편집 차종을 __init__이 실제로이 작업을 수행 할 장소가 아니라는 점도 분명합니다. 잊지 마십시오. 일반적인 쿼리 세트를 평가하더라도 모델 객체를 인스턴스화합니다. 이는 __init__을 호출한다는 것을 의미합니다. 따라서 데이터베이스에서 인스턴스를 가져 오는 것만으로도 문제가 발생합니다. 이러지 마.당신은 정말이 필요하면

대신에, 모델에 의해 제공 될 - 위와 같이이 코드의 한 라인에도 불구하고 - 당신이 classmethod 정의 할 수 있습니다 :

class Question(models.Model): 
    ... 
    @classmethod 
    def query(cls, text): 
     question, _ = cls.objects.get_or_create(text=text, defaults={'asked': True}) 
     return question 

이 그럼 당신은 Question.query('How are you')을 할 수 및 새 항목이나 기존 항목을 반환합니다.

+0

내부에 인스턴스를 덮어 쓰는 것이 무의미하다고 지적한 Daniel에게 감사드립니다! 그러나, 나는 질문 ('myquestion')과 같은 것을 쓸 수 있도록 인스턴스를 반환하는 데 + 뒤에 __ init__ 메서드 (eventhough 그것은 권고하지 않습니다 :-))를 덮어 쓸 수 있고 싶습니다. 장면. 내 질문을 수정하여 목표를 명확하게했습니다. – forbo

+0

명확한 답변을 보내 주셔서 감사합니다. – forbo

0

__init__ 내의 로직은보기와 같이 다른 곳으로 이동해야합니다. get_or_create은 1) 객체와 2) 객체를 생성해야하는지 여부와 같은 두 값을 반환합니다. See the docs for more details.

def some_view(request): 
    c, created = Question.objects.get_or_create(text=text) 

    if not created: 
     print 'This question was already asked' 
    else: 
     print 'This question will be asked!' 
     c.asked = True 
     c.save() 
+0

감사합니다. Scott! 코드의 해당 부분을 다른 함수 나 메서드 (예 : my_init)로 옮기면 모든 문제가 사라질 것입니다. 그러나, 나는 정말 질문을 작성할 수 있도록 \ __init를 오버라이드하려고합니다. = Question ('myquestion'). 나는 그것을 명확하게하기 위해 나의 질문을 편집했다. – forbo

0

@Scott Woodall처럼, 당신은 init 논리를 움직여야합니다. 그게 무슨 일 이니 :

Question('how are you?')로 전화하면 __init__ 방법으로 이동합니다. 그 textQuestion을 찾을 수 있도록 새로운 질문을 만들려고 does't __init__ 전화 Question.objects.get_or_create(text=text), __init__ (다시)를 호출. 메서드 호출에서 다시 입력하고 있습니다.

Question('how are you?') # <-- You call this method 
    | 
    +-- def __init__(self, text, *args): 
     | 
     +-- Question.objects.get_or_create(text=text) # This try to create a model, calling __init__ method! 
      | 
      +-- def __init__(self, text, *args): 
       | 
       +-- Question.objects.get_or_create(text=text) # This try to create a model, calling __init__ method! 
        | 
        + # So on... 

텍스트 입력란에 unique=True을 추가해야한다고 생각합니다.

참조 @Scott 응답

+0

시간 내 주셔서 감사합니다. 이것은 실제로 일어나는 일입니다! 그러나 이것은 불행히도 \ __ init__을 오버라이드 (override)하는 방법의 문제를 해결하지 못하기 때문에 Question ('myquestion')을 작성하고 뒤에서 수행되는 db 작업을 수행 할 수 있습니다. 나는 그것을 명확하게하기 위해 나의 질문을 편집했다. – forbo

관련 문제