发布
社区首页 >问答首页 >扩展Django用户模型-表单总体错误

扩展Django用户模型-表单总体错误
EN

Stack Overflow用户
提问于 2017-05-15 18:10:34
回答 1查看 120关注 0票数 0

我正在用Player类扩展Django的(v1.9)内置用户模型,以添加一些额外的属性。

代码语言:javascript
代码运行次数:0
复制
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并不完全匹配。结果发现,在填充与Player相关的模型的ModelForms时,这会导致一个问题,例如:

代码语言:javascript
代码运行次数:0
复制
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匹配时,没有问题,在表单中填充了Player ID,并成功地创建了城市。当用户ID和Player ID不同时,未在表单中填充player ID,表单将失败,城市创建也将失败。

从request.user获得玩家ID是没有问题的,在获得POST数据之后,我可以在验证之前修复玩家ID。我还添加了一个保存后挂钩,以便玩家总是被创建,所以ID将永远匹配。但是,似乎表单应该首先使用player ID填充,因为用户数据是可访问的,并且是一对一的关系。

我在这里错过了什么?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-05-15 18:25:04

您所缺少的是,当您实例化一个ModelForm以创建一个与某些现有对象相关的新行时,Django无法知道相关对象的id。你得想办法告诉我。

这样做的一种方法是,当您响应GET显示表单时,对表单构造函数使用initial参数:

代码语言:javascript
代码运行次数:0
复制
myform = MyModelFormClass(None, initial={ 'myfkfield': myrelatedobject.pk })

现在,表单类知道在呈现表单时要预先填写的值,以及表单发布时,该字段将与其一起发布。

另一种方法是将关系字段从表单中完全省略,然后在保存之前填充它,方法是使用表单保存方法的commit参数:

代码语言:javascript
代码运行次数:0
复制
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()

请注意,这将用于插入。对于更新,需要将现有对象提供给模型表单构造函数,如下所示:

代码语言:javascript
代码运行次数:0
复制
myinstance = MyModel.objects.get(pk=self.kwargs.pk)
myform = MyModelFormClass(request.POST, instance=myinstance)

如果没有实例,ModelForm就不知道它在数据库中更新的是哪一行。您可能会认为这些都在HTML中,所以不应该是必要的。但Django不是这样工作的。您需要从数据库中获取存在的对象,并将其与ModelForm数据一起传递给request.POST构造函数。然后,当您调用myform.save()时,它将验证表单,将其数据与现有对象合并,并保存该对象。使用commit=False将导致这三个步骤中的最后一个被推迟,这样您就可以在实际保存更新的实例之前对其进行任何调整或检查。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43986173

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档