如何模仿 django admin 的 OneToOneField 可选表单

Posted

技术标签:

【中文标题】如何模仿 django admin 的 OneToOneField 可选表单【英文标题】:How to imitate django admin's OneToOneField optional form 【发布时间】:2011-09-25 15:15:36 【问题描述】:

我想模仿 Django 管理站点在模型具有 OneToOneField 到另一个模型时提供的功能,在该模型中填写 OneToOne 模型的表单是可选的。该字段的表单始终显示,但如果它为空,则不会创建 OneToOneField 的对象,只会创建或修改主对象。它还有一个删除复选框,仅在创建 OneToOneField 对象时才激活。如果选中它并点击保存,则 OneToOne 对象将被删除,但主要对象会被保留。

涉及的模型:一个是产品,另一个是产品的额外信息,如果它恰好是啤酒:

class Producto(models.Model):
    nombre = models.CharField(max_length=100, blank=False)

class Cerveza(models.Model):
    producto = models.OneToOneField(Producto)

这是我尝试对视图执行的操作:

def productomodificar(request, producto_id):
    from django.forms.models import inlineformset_factory
    from pdv.models import Producto, Cerveza
    from pdv.forms import ProductoForm, CervezaForm

    ProductoFormSet = inlineformset_factory(Producto, Cerveza, can_delete=True, form=CervezaForm)

    alerta = None
    producto = get_object_or_404(Producto, pk=producto_id)
    if request.user.is_staff:
        if request.method == 'POST':
            form = ProductoForm(request.POST, instance=producto)
            cervezaform = ProductoFormSet(request.POST, instance=producto)
            if form.is_valid():
                if cervezaform.is_valid():
                    form.save()
                    cervezaform.save()
                    alerta = "Producto modificado exitosamente"
                else:
                    alerta = "Error al modificar datos de cerveza"
            else:
                alerta = "Error al modificar producto"

        else:
            form = ProductoForm(instance=producto)
            cervezaform = ProductoFormSet(instance=producto)
            getm = request.GET.get('m', None)
            if getm == '1':
                alerta = "Producto creado exitosamente"
    else:
        alerta = "No tienes permiso para editar productos"
        form = producto
    c = "user": request.user, "titulo": "Administrar Producto", "form": form, "cervezaform":cervezaform, "alerta":alerta
    c.update(csrf(request))
    return render_to_response("productomodificar.html",c)

这些是我参与的表格:

class ProductoForm(ModelForm):
    class Meta:
        from pdv.models import Producto
        model = Producto

class CervezaForm(ModelForm):
    class Meta:
        from pdv.models import Cerveza
        model = Cerveza

这就是我设法在模板中显示两个表单的方法:

<form method="post" action="">% csrf_token %
    <table>
         form.as_table 
         cervezaform.as_table 
        <tr>
            <th></th>
            <td><input type="submit" value="Guardar" /></td>
        </tr>
    </table>
</form>

但问题仍然是,如果我不填写 OneToOne 表格 (Cerveza),我将无法添加产品。所以,不能为空。此外,如果我尝试删除 OneToOne 表单,我会收到以下消息:

(Hidden field id) Select a valid choice. That choice is not one of the available choices.

不幸的是,我找不到一个很好的例子来说明如何为可选的 OneToOneField 创建表单并在自定义模板中使用它。

我给你留下两个例子来说明它在 django admin 中是如何工作的:

在添加可选的 onetoone 对象之前:http://i.imgur.com/p3P6s.png

创建可选onetoone对象后:http://i.imgur.com/UEcm8.png

我将非常感谢任何帮助。提前致谢。

【问题讨论】:

【参考方案1】:

您需要更改一件小事以使您的代码完美运行。发布表单并保存数据后,您应该重定向到某个地方,而不是再次显示表单。替换:

    alerta = "Producto modificado exitosamente"

与:

    from django.shortcuts import redirect
    return redirect('my_view')

(您可以使用return redirect('pdv.views.productomodificar', prodcuto.id) 重定向回表单)

【讨论】:

谢谢。这就是我需要的答案。虽然我更喜欢使用 HttpResponseRedirect("/producto/%s/" % producto.id) 这样我就不必处理 id 错误,而且 OneToOneField 确实会被更新或删除。如果我不能为你的答案投票,请原谅我,我没有足够的声誉。 见:meta.stackexchange.com/questions/5234/…

以上是关于如何模仿 django admin 的 OneToOneField 可选表单的主要内容,如果未能解决你的问题,请参考以下文章

django-admin和manage.py用法

如何使用 google-appengine 和 django-nonrel 模仿“select_related”?

模仿 Django 管理界面样式的 jQuery 主题(使用 CSS)[关闭]

Django Admin Cookbook-8如何在Django admin中优化查询

如何将 django-admin-bootstrapped 与 django 1.10 集成

Django Admin Cookbook-38如何获取特定对象的Django Admin后台URL