簡體   English   中英

擴展Django用戶模型-表單填充錯誤

[英]Extending Django User model - form population errors

我正在使用Player類擴展Django(v1.9)的內置User模型,以添加一些額外的屬性。

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管理面板創建用戶時,我並非總是需要創建播放器,因此有時僅會創建User。 結果,播放器和用戶ID不完全匹配。 事實證明,這在填充鏈接到Player的模型的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,該表單無法驗證,並且創建城市失敗。

我沒有從request.user獲取播放器ID的問題,並且可以在獲取POST數據后在驗證之前修正播放器ID。 我還添加了一個后保存掛鈎,以便始終創建Player,因此ID始終匹配。 但是似乎表單應該首先以玩家ID填充,因為用戶數據可以訪問並且是一對一的關系。

我在這里想念什么?

您所缺少的是,當實例化一個ModelForm來創建與某個現有對象相關的新行時,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導致這三個步驟中的最后一個被推遲,因此您可以在實際保存更新后的實例之前對其進行任何調整或檢查。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM