【问题标题】:ModelForm right approach for editing database record?ModelForm 编辑数据库记录的正确方法?
【发布时间】:2016-05-18 15:06:48
【问题描述】:

有人可以帮我修复 Django ModelForm 吗?

此特定代码可以按预期将新项目添加到数据库,但是当我尝试编辑数据库记录时 - 它只是添加新记录,而不是更新旧记录。我是 Django 框架的新手。

views.py:

def manage(request, item_id = None):
    t = get_object_or_404(Hardware, id=item_id) if item_id else None
    form = Manage(request.POST or None, instance=t)

if t:
    if form.is_valid():
        #form.save()
        hostname = form.cleaned_data['hostname']
        cpu = form.cleaned_data['cpu']
        os = form.cleaned_data['os']
        ram = form.cleaned_data['ram_total']
        storage = form.cleaned_data['storage']
        hostdata = Hardware(
        hostname=hostname,
        cpu=cpu,
        ram_total=ram,
        os=os,
        storage=storage,
        lock_state=t.lock_state, # because in edit operation we shouldn't change it.
        lock_date=t.lock_date, # because in edit operation we shouldn't change it.
        locked_by=t.locked_by) # because in edit operation we shouldn't change it.
        hostdata.save()
        return HttpResponseRedirect(reverse('main:index'))
elif not t:
    if form.is_valid():
        hostname = form.cleaned_data['hostname']
        cpu = form.cleaned_data['cpu']
        os = form.cleaned_data['os']
        ram = form.cleaned_data['ram_total']
        storage = form.cleaned_data['storage']
        current_user = request.user
        user = User.objects.get(id=current_user.id)
        hostdata = Hardware(
        hostname=hostname,
        cpu=cpu,
        ram_total=ram,
        os=os,
        storage=storage,
        lock_state=0,
        lock_date=datetime.datetime.now(),
        locked_by=user)
        hostdata.save()
        return HttpResponseRedirect(reverse('main:index'))

return render(request, 'hardware/edit.html', {'form': form})

models.py:

class Hardware(models.Model):
    hostname = models.CharField(max_length=255, default=None)
    os = models.CharField(max_length=255, default=None)
    cpu = models.CharField(max_length=255, default=None)
    ram_total = models.CharField(max_length=255, default=None)
    storage = models.CharField(max_length=255, default=None)
    lock_state = models.BooleanField(default=0)
    locked_by = models.ForeignKey(User)
    lock_date = models.DateTimeField(default=None)
    alive = models.BooleanField(default=0)

class Meta:
    db_table = "hardware"

def __str__(self):
    return self.hostname

forms.py:

class Manage(forms.ModelForm):
    class Meta:
        model = Hardware
        fields = ['hostname', 'os', 'cpu', 'ram_total', 'storage']

urls.py:

url(r'^manage/new/$', views.manage, name='add'),
url(r'^manage/edit/(?P<item_id>[0-9]+)/$', views.manage, name='edit')

模板:

<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Save!" />
</form>

【问题讨论】:

    标签: python django web django-forms modelform


    【解决方案1】:

    我认为这样的事情 - 使用 update_fields - 应该可以工作:

    def manage(request, item_id = None):
        t = get_object_or_404(Hardware, id=item_id)
        form = Manage(request.POST or None, instance=t)
    
    if t:
        if form.is_valid():
            #form.save()
            t.hostname = form.cleaned_data['hostname']
            t.cpu = form.cleaned_data['cpu']
            t.os = form.cleaned_data['os']
            t.ram = form.cleaned_data['ram_total']
            t.storage = form.cleaned_data['storage']   
            t.save(update_fields=['hostname', 'cpu', 'os','ram','storage'])
            return HttpResponseRedirect(reverse('main:index')) 
    ........
    

    【讨论】:

      【解决方案2】:

      您已经在视图的第一行检索到实例t。下面的代码总是会创建一个新的实例(除非你指定了pk参数):

       hostdata = Hardware(...)
       hostdata.save()
      

      只需这样做:

       if t:
           if form.is_valid():
               t.hostname = form.cleaned_data['hostname']
               t.cpu = form.cleaned_data['cpu']
               ....
               t.save()
      

      但是,正如其他答案所建议的那样,您确实应该依赖ModelForm 提供的save 方法。这是一个例子:

       def manage(request, item_id=None):
           t = get_object_or_404(Hardware, id=item_id) if item_id else None
      
           # if t is None, a new object will be created in form.save()
           # if t is an instance of Hardware, t will be updated in form.save()
           form = Manage(request.POST, instance=t)
      
           if form.is_valid():
               form.save()
               return HttpResponseRedirect(reverse('main:index')
      
           return render(request, 'hardware/edit.html', {'form': form})
      

      您还在表单中指定了fields

      fields = ['hostname', 'os', 'cpu', 'ram_total', 'storage']
      

      这些是当您调用form.save() 时将设置或更新的字段。

      【讨论】:

      • 谢谢,但是我怎样才能使用这种方法进行单独的行为,例如 1. 当我创建新记录时 - 我正在为表单中不存在的 db 行使用一些默认值。 2. 当我使用编辑表单时 - 不要更改这些值并在数据库中保持原样?
      • 仅更新fields = [...] 中指定的字段。在您的表单中,lock_statelock_datelocked_by 永远不会被表单更新,即使 request.POST 中存在数据。
      • 对于创建新模型的默认值,您有两种选择:1. 在 models.py 中设置默认值,或者 2. 使用 hardware = form.save(commit=False) 并修改 hardware 以适应您的需求致电hardware.save()之前需要。
      • 我能够修复数据库默认字段以创建新项目,但注意到以下错误: 1. 当您打开任何表单(创建/编辑)时 - “此字段是必需的。”总是显示错误。 2.由于某种原因编辑表单没有填充数据库中的数据。我使用了您示例中的视图,这是模型的固定部分:locked_by = models.ForeignKey(User, default=lambda: User.objects.get(id=1)) lock_date = models.DateTimeField(default=datetime.datetime.now())
      • 您看到的错误信息是由form.is_valid()引起的。您需要处理 http post 并单独获取。 http get 应该在不调用form.is_valid() 的情况下呈现页面。我在gist.github.com/derekkwok/c0b8cdb32b8333364318 添加了一个示例实现
      【解决方案3】:

      尝试基于类的视图,它最简单的样子如下:

      from django.views import generic
      class HardwareEditView(generic.UpdateView):
      
          template_name = "hardware.html"
          form_class = Manage
      

      您必须将 get_absolute_url 添加到模型中。 基于通用类的视图正是用于此标准的创建/更新/查看常见任务。

      【讨论】:

      • 是的,我在基于类的视图之前尝试过,但无法使用数据库中的数据填充编辑表单。会再试一次。
      • 我需要一些时间来适应它,但一旦你习惯了,你就不会回头。设置一个表单、一个查询集、一个模板和哎呀......它正在工作。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-06-13
      • 2021-10-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-24
      • 1970-01-01
      相关资源
      最近更新 更多