问题描述
我最近在我的游戏模型中添加了一个“用户”字段。我可以创建一个运行良好的新游戏;就是在我希望允许用户编辑我遇到问题的游戏实例时。我的观点是在form = GameForm(request.POST,instance=game)
处调用game = Game.objects.get(pk=id)
。表单已预先填充了正确的数据,但是在提交表单后,无论是否有更新,表单都不会生效。它将其视为POST,但无法进入if form.is_valid()
条件内部。自从我添加了用户字段以来,这一直是。我正在使用默认的Django用户模型,字段名称称为“所有者”。由于用户可以拥有许多游戏,并且游戏可以被许多用户拥有,因此将其设置为ManyToManyField(User,blank=True)
。 Django构成了“多对多”“通过”表,但是我不希望用户能够更改谁拥有什么。我将其作为forms.py
中的隐藏字段,因此用户无法更改。
模型
class Game(models.Model):
game_title = models.CharField(max_length=100,verbose_name='Game Title',db_column='game',blank=False,null=False,unique=True)
game_developer = models.CharField(max_length=100,verbose_name='Developer',db_column='developer',blank=True,null=True)
game_release = models.DateField(max_length=50,verbose_name='Release Date',db_column='release_date',null=True)
rating = models.IntegerField(verbose_name='Game rating',db_column='rating',choices=INT_CHOICES,null=True)
game_genre = models.CharField(max_length=100,verbose_name='Genre',db_column='genre',null=True,choices=GENRE_CHOICES)
game_platform = models.CharField(max_length=100,verbose_name='Game Platform',db_column='platform',choices=PLATFORM_CHOICES)
game_esrb = models.CharField(max_length=100,verbose_name='ESRB rating',db_column='esrb',null=True)
owner = models.ManyToManyField(User,blank=True)
objects = models.Manager()
def __str__(self):
return self.game_title
class Meta:
db_table = 'tbl_games'
verbose_name = 'Game'
查看
# Allows the user to update game information
def editGame(request,id):
# Finds the user selected game by game id
game = Game.objects.get(pk=id)
user = request.user.id
if request.method == 'POST':
print("Seen as POST")
# Create game instance pre-populated into a form
form = GameForm(request.POST,instance=game)
if form.is_valid():
print("Form is valid!")
# Saves the edits without saving to the dB
form.save()
messages.success(request,'Game successfully updated!')
return redirect('library')
else:
print('Seen as GET')
form = GameForm(instance=game)
print("Page loaded")
context = {'form': form}
return render(request,'library/editGame.html',context)
表格
class GameForm(ModelForm):
game_esrb = forms.CharField(required=False,widget=HiddenInput)
owner = forms.Hiddeninput()
def __init__(self,*args,**kwargs):
super(GameForm,self).__init__(*args,**kwargs)
class Meta:
model = Game
fields = [
'game_title','game_developer','rating','game_release','game_genre','game_platform','game_esrb','owner'
]
widgets = {
'rating': Select(attrs={'choices': INT_CHOICES}),'game_genre': Select(attrs={'choices': GENRE_CHOICES}),'game_platform': Select(attrs={'choices': PLATFORM_CHOICES}),'esrb_rating': Hiddeninput(),'owner': HiddenInput
}
help_texts = {
'rating':
'Key: 1 - Bad | 2 - Okay | 3 - Average | 4 - Good | 5 - Great'
}
模板
{% block appcontent %}
<div class="height">
<form method="POST">
{% csrf_token %}
{{ form|crispy }}
<div class="form-btn">
<a class=" btn btn-secondary cancel" type="button" href="{% url 'library' %}">Cancel</a>
<button class="update btn btn-primary" type="submit">Update</button>
</div>
</form>
</div>
{% endblock %}
解决方法
首先,从分配给GameForm类中的字段的列表中删除“所有者”:
class Meta:
model = Game
fields = [
'game_title','game_developer','rating','game_release','game_genre','game_platform','game_esrb',# 'owner' removed
]
原因如下:在ModelForm中,您只需要在表单中命名要用作输入字段的游戏字段 。在您的情况下,您实际上并不希望将“所有者”字段用作输入字段,因此只需将其排除在此列表之外即可。这将实现您规定的禁止用户修改所有者字段的目标。
现在让我们查看并修改您的视图:
-
您可以在视图中执行此操作:“ user = request.user.id”这将为属性'user'分配一个int。我猜想您想要一个用户对象,而不是一个int,但目前还不清楚,因为您实际上从未在视图中的任何地方使用此属性。
-
这是需要发生的事情:视图需要将用户对象连接到游戏对象,然后保存游戏对象。我们已经确保“所有者”不会在表单中显示为输入字段。现在,我们需要为该字段手动提供一个值,然后保存该对象。下面,我们在您视图中的is_valid()调用之后执行此操作:
def editGame(request,id): # Finds the user selected game by game id game = Game.objects.get(pk=id) if request.method == 'POST': print("Seen as POST") # Create game instance pre-populated into a form form = GameForm(request.POST,instance=game) if form.is_valid(): print("Form is valid!") form.save() game.owner.add(request.user) # update the game's owner field,assigning the current user game.save() messages.success(request,'Game successfully updated!') return redirect('library')
总结并阐明:所有这些工作的最终结果是更新了Game对象。用户通过ModelForm更新值。该视图将验证这些更改,然后保存表格,并保存相应的游戏对象。然后,我们将用户手动分配到游戏的“所有者”字段,因为我们有意将该字段从表单中删除。然后我们再次保存游戏,以便此更改包含在对象的“最终”状态。