繁体   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