ModelForm 编辑数据库记录的正确方法?

ModelForm right approach for editing database record?

有人可以帮我修复 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>

尝试基于 Class 的视图,最简单的视图如下所示:

from django.views import generic
class HardwareEditView(generic.UpdateView):

    template_name = "hardware.html"
    form_class = Manage

您必须将 get_absolute_url 添加到模型中。 基于 class 的通用视图完全适用于此标准 create/update/view 常见任务。

您已经在视图的第一行检索到实例 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() 时设置或更新。

我认为这样的事情 - 使用 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')) 
........