Django编辑表单不会在带有用户字段的form.save()上进行验证

2024-04-24 07:48:39 发布

您现在位置:Python中文网/ 问答频道 /正文

我最近在我的游戏模型中添加了一个“用户”字段。我可以创造一个新的游戏,工作良好;当我想允许用户编辑我遇到问题的游戏实例时。我的视图正在调用form = GameForm(request.POST, instance=game),其中game = Game.objects.get(pk=id)。表单预先填充了正确的数据,但在提交表单时,无论是否有更新,表单都不会进行验证。它将其视为POST,但无法进入if form.is_valid()条件。这是自从我添加用户字段以来。我使用的是默认的Django用户模型,字段名为“owner”。它被设置为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',
                                    blank=False,
                                    null=True)
    rating = models.IntegerField(verbose_name='Game Rating',
                                 db_column='rating',
                                 choices=INT_CHOICES,
                                 blank=True,
                                 null=True)
    game_genre = models.CharField(max_length=100,
                                  verbose_name='Genre',
                                  db_column='genre',
                                  blank=False,
                                  null=True,
                                  choices=GENRE_CHOICES)
    game_platform = models.CharField(max_length=100,
                                     verbose_name='Game Platform',
                                     db_column='platform',
                                     blank=True,
                                     choices=PLATFORM_CHOICES)
    game_esrb = models.CharField(max_length=100,
                                 verbose_name='ESRB Rating',
                                 db_column='esrb',
                                 blank=False,
                                 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 %}

Tags: 用户nameformgametrueverbosedbmodels
1条回答
网友
1楼 · 发布于 2024-04-24 07:48:39

首先,从分配给GameForm类中字段的列表中删除“所有者”:

class Meta:
    model = Game
    fields = [
        'game_title', 'game_developer', 'rating', 'game_release',
        'game_genre', 'game_platform', 'game_esrb',      # 'owner' removed
    ]

原因如下:在模型表单中,只需命名要用作表单中输入字段的游戏字段。在您的情况下,您实际上不希望“所有者”字段成为输入字段,所以请将其从列表中删除。这将实现您声明的不允许用户修改所有者字段的目标

现在让我们查看并修改您的视图:

  1. 您可以在视图中执行此操作:“user=request.user.id”这将为属性“user”分配一个int。我猜您想要的是用户对象,而不是int,但这并不清楚,因为您从来没有在视图中的任何位置使用过该属性

  2. 需要做的是:视图需要将用户对象连接到游戏对象,然后保存游戏对象。我们已经确保“所有者”不会在表单中显示为输入字段。现在,我们需要手动为该字段提供一个值,然后保存该对象。下面,我们在视图中执行以下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')
    

总结并澄清:所有这些工作的最终结果是更新了游戏对象。用户通过ModelForm更新值。视图验证这些更改,然后保存表单,从而保存相应的游戏对象。然后,我们手动将用户分配到游戏的“所有者”字段,因为我们有意将该字段保留在表单之外。然后我们再次保存游戏,以便将此更改包含在对象的“最终”状态中

相关问题 更多 >