0

これは、stackoverflow に関する私の最初の投稿であるため、質問の仕方についての批判は大歓迎です。

私のコードでは、次のエラーが発生します。

RuntimeError: maximum recursion depth exceeded

これがコードです(内容は関係ありません。可能な限り簡単な方法でエラーを再現しただけです)。基本的に私は __init__ をオーバーライドしようとしています。オブジェクトがデータベースにある場合は何かを行い、そうでない場合は別のことをしたいと思います。

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

コンストラクターを呼び出すときにエラーが発生します。

Question('how are you?')

問題が get_or_create メソッドにあることは理解しています。エラーメッセージを見ると、

---> 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__ をオーバーライドすることだと思います。それは可能ですか、それとも概念的に間違っていますか (またはその両方)? ありがとう!

4

3 に答える 3

2

でこれを実際に試してはいけません__init__。(実際、__init__Django モデルの はそのままにしておくのが最善です。) フォームまたはビューに入れる必要があります。

いずれにせよ、代入によってそれ自体の内部のインスタンスを上書きすることはできません。selfこれは他の変数と同様に単なるローカル変数であり、メソッドの最後でスコープから外れます。

defaultsまた、パラメータを使用しget_or_createて、既存のインスタンスが見つからない場合に新しいインスタンスに設定されるデフォルト値を渡すことができることに注意してください。

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

質問の更新後に__init__編集してください。あなたの編集は、実際にこれを行う場所ではないことをさらに明確にします。通常のクエリセットを評価してもモデル オブジェクトがインスタンス化されることを忘れないでください。つまり、呼び出しを意味__init__します。そのため、データベースからインスタンスを取得するだけで問題が発生します。これをしないでください。

代わりに、モデルによってこれを提供することが本当に必要な場合は、上記のように 1 行のコードであっても、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')次に、新しいアイテムまたは既存のアイテムのいずれかを返すことができます。

于 2013-07-02T13:26:51.190 に答える
0

ビューのように、ニーズ内のロジックを__init__別の場所に移動する必要があります。get_or_create2 つの値を返します: 1) オブジェクトと 2) オブジェクトを作成する必要があったかどうか。詳細については、ドキュメントを参照してください。

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()
于 2013-07-02T13:20:19.103 に答える
0

@Scott Woodallが言ったように、initロジックを移動する必要があります。それは何が起こっているのですか:

を呼び出すとQuestion('how are you?')__init__メソッドに移動します。そので を見つけられない呼び出し__init__は、 (再度)呼び出して、新しい質問を作成しようとします。メソッド呼び出しを永久に再入力しています。Question.objects.get_or_create(text=text)Questiontext__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の回答を参照してください

于 2013-07-02T13:32:39.570 に答える