2017-05-15 17 views
0

追加のプロパティを追加するために、Django(v1.9)ビルトインユーザーモデルをPlayerクラスで拡張しています。Djangoを拡張するユーザーモデル - フォームの人口エラー

class Player(models.Model): 
    TIMEZONES=() 
    user = models.OneToOneField(User, on_delete=models.CASCADE) 
    ... (player-specific properties here) 
    time_zone = models.CharField(max_length=255, choices=PRETTY_TIMEZONE_CHOICES, blank=True, null=True,) 

Djangoの管理パネルからユーザーを作成する場合、必ずしもプレイヤーを作成する必要はないため、ユーザーのみ作成されることがあります。その結果、プレーヤーIDとユーザーIDが正確に一致しません。このように、プレイヤーにリンクされたモデルのModelFormsを移入するとき、これは問題につながることが判明:新しい都市を作成するときに

class City(models.Model): 
    player = models.ForeignKey(Player, on_delete=models.CASCADE) 
    name = models.CharField(max_length = 100) 
    x_coord = models.SmallIntegerField() 
    y_coord = models.SmallIntegerField() 
    region = models.CharField(max_length = 100) 
    def __unicode__(self): 
     return str(self.player) + "-" + str(self.name) 
    class Meta: 
     db_table = 'cities' 

class CityForm(ModelForm): 
    class Meta: 
     model = City 
     fields = (
      'name', 
      'player', 
      'x_coord', 
      'y_coord', 
      'region') 

これのModelFormが使用されています。ユーザーIDとプレーヤーIDが一致すると問題はなく、プレーヤーIDがフォームに入力され、都市が正常に作成されます。ユーザーIDとプレーヤーIDが異なる場合、プレーヤーIDはフォームに入力されず、フォームは検証されず、都市の作成は失敗します。

Player IDをrequest.userから取得するのに問題はなく、POSTデータを取得した後に検証する前にプレーヤーIDを修正できます。また、Playerが常に作成されるようにポストセーブフックを追加したので、IDは常に一致します。しかし、ユーザデータにアクセス可能で、1対1の関係であるため、フォームに最初にプレーヤIDを入力する必要があります。

私はここで何が欠けていますか?

答えて

0

モデルフォームをインスタンス化して既存のオブジェクトに関連する新しい行を作成すると、Djangoは関連オブジェクトのIDを知ることができません。あなたは何とかそれを伝える必要があります。あなたがGETに応じて、フォームを表示しているとき、それをする

一つの方法は、ある、フォームのコンストラクタにinitial引数を使用します。

myform = MyModelFormClass(None, initial={ 'myfkfield': myrelatedobject.pk }) 

今すぐフォームクラスはフィルを事前にどのような価値を知っていますフォームがレンダリングされるときに、フォームがポストされるときに、そのフィールドはそれと共にポストされます。

それを行うために他の方法は、メソッドの保存形式にcommit引数を使用することによって、あなたが保存する前に、後でそれを記入し、その後、完全に自分のフォームから関係フィールドを省略することになります。

myform = MyModelFormClass(request.POST) 
# this causes form values to be filled into the instance without actually 
# writing to the database yet. 
myinstance = myform.save(commit=False) 
myinstance.myfkfield = myrelatedobject 
# now really write to database 
myinstance.save() 

注意これは挿入のためのものであることを示します。更新については、あなたはこのように、あなたのModelFormのコンストラクタに既存のオブジェクトを提供する必要があります。

myinstance = MyModel.objects.get(pk=self.kwargs.pk) 
myform = MyModelFormClass(request.POST, instance=myinstance) 

インスタンスがなければ、のModelFormは、それがデータベースに更新何行知りません。これはHTML内にすべて存在するので、必要ではないはずですが、Djangoの仕組みではありません。データベースから既存のオブジェクトをフェッチし、request.POSTデータとともにModelFormコンストラクターに渡す必要があります。その後、myform.save()を呼び出すと、フォームが検証され、既存のオブジェクトとデータがマージされ、オブジェクトが保存されます。 commit=Falseを使用すると、最後の3つのステップが遅延されるため、実際に保存される前に更新されたインスタンスを調整またはチェックできます。

+0

私はIDに関して何の仮定もしていませんでしたが、まったく反対です。私は、プレーヤーIDがmodelFormに正しく設定されると考えていました。この問題は複数の市区町村IDではなく、ユーザーのプレーヤーIDが都市作成フォームに入力されない新しい都市を作成するときです。 – seadeer

+0

ああ、私はあなたの問題を回避しようとしていた、私は私の答えを更新する –

+0

私は私の答えを変更しましたので、うまくいけば、これは参考になります。あなたがまだ理解していない場合は、私はそれをクリアしようとすることができます。 –

関連する問題