2009-07-28 106 views
13

は例です:Djangoのmanytomanyフィールドを更新するには?ここ

私は、これらのクラスのデータベースで

class Author(models.Model): 
    name = models.CharField(max_length=45) 

class Book(models.Model): 
    name = models.CharField(max_length=45) 
    authors = models.ManyToManyField(Author) 

を持っている場合、私は名前を「ジョージ」と名「Georfe」と別のものと1本の著者を持っています。最後のものは間違いです。だから私が望むのは、著者の一人として "Georfe"を持っているすべての本に、 "George"という著者がそれを置き換えることです。

SQLでは、本当に簡単です。 「ジョージ」= 3のIDと「Georfe」= 7のIDと関係のテーブル名が「author_book」の場合:

UPDATE author_book SET id=3 WHERE id=7; 

それはDjangoのORMであることを行うことは可能ですか? Iループトラフ入力ミス著者のすべての関連書籍と実行します:

は、私はそれを行うための方法を見つけ

book.authors.add(Author.objects.get(id=3)) 
book.authors.remove(Author.objects.get(id=7)) 

しかし、私はこのソリューションは本当にエレガントかつ効率的に見つけることはありません。ループのないソリューションはありますか?

+0

いくつかのタイプミスを修正するためにこれが一度に行われるのであれば、生のSQLを実行するだけではどうですか? – thedz

+0

データベース内のデータは古いファイルメーカーDBから取得されており、修正するために多くのタイプミスがあります。私は自分ですべてのタイプミスを修正したくありません。私はクライアントが管理インターフェースでそれを行うことができたらいいと思う。 – Etienne

答えて

14

注:このコードはを削除します悪い 'georfe'作者だけでなく、正しい著者を指すように本を更新しています。それをしたくない場合は、.remove()を@ jcdyerの答えとして使用してください。

このようなことはできますか?

george_author = Author.objects.get(name="George") 
for book in Book.objects.filter(authors__name="Georfe"): 
    book.authors.add(george_author.id) 
    book.authors.filter(name="Georfe").delete() 

私は(キーワード引数「スルー」で)あなたは二つのモデルを結合し、明示的なテーブルを持っていた場合、これは容易になるだろうと思われる - その場合、あなたは直接関係テーブルへのアクセス権を持っているでしょうし、その上に.update(id=george_author.id)を行うことができます。

+0

jcdへの私のコメントを参照してください、あなたのソリューションはほとんど同じです(削除を除いて、私は間違って削除する必要はありません。 私はあなたの解決策が正しい方法であると思います。私はこの答えを受け入れる。残念ながら、私がModelAdminを拡張し、すべてが汎用的でなければならないので、私のケースはもっと複雑です。私は関係テーブルを直接使用することはできません。( "トラフ"引数が設定されているかどうかはわかりません。私は正しい? – Etienne

+0

インスタンスでは、 'through'引数を見ることができます:book.authors.through = 'ModelName' - クラス自体を介してアクセスできるかどうかはわかりません。 –

+0

インスタンスの「スルー」引数をチェックし、ManyToManyFieldに設定されていない場合、スルーはNoneです。ですから、私はループの解を追加/削除(または削除)しておきます。多分それはエレガントで効率的ではありませんが、私たちのニーズに十分対応しています。 おかげでイアン、JCD – Etienne

14

自動生成されたスルーテーブルでは、2段階の挿入と削除を行うことができます。これは可読性に優れています。

george = Author.objects.get(name='George') 
georfe = Author.objects.get(name='Georfe') 

book.authors.add(george) 
book.authors.remove(georfe) 
assert george in book.authors 

あなたが明示的にテーブルを介して定義している場合(著者= models.ManyToManyField(著、= BookAuthors)、あなたがBookAuthorに明示的に関係を変更することができます。ほとんど知られていない事実は、このモデルがすでに存在していること、それを通じあなたは(マルチ著者の本の中で、例えば特定の著者が書いた章)を保存したい余分なデータを持っている場合は、自動的に。通常、あなたが唯一のモデルによって、明示的に作成する必要がありますジャンゴによって生成される。

# This line is only needed without a custom through model. 
BookAuthor = Book.authors.through 
book_author = BookAuthor.objects.get(author=georfe, book=great_american_novel) 
book_author.author = george 
book_author.save() 
assert george in book.authors 
+0

ハ、私たちはほぼ同時に同じことを書いています!しかし、私はManyToManyFieldの "トラフ"引数について知らなかった。私はそれを調べます。しかし、イアンが更新との関係表を使用する方法は、より効力があるようです。 – Etienne

関連する問題