如何模仿django admin的OneToOneField可选表单
我想模仿 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 对象之前: https:// /i.sstatic.net/suMEc.png
创建可选的 onetoone 对象后:https://i.sstatic.net/qxNtd.png
我将非常感谢任何帮助。提前致谢。
I would like to imitate the functionality that the Django Admin site offers when a model has a OneToOneField to another model, where it is optional to fill the form for the OneToOne model. The form for that field is always shown, but if it is empty, a OneToOneField's object is not created, only the main object is created or modified. It also has a delete checkbox, which is only activated when the OneToOneField object has been created. If it is checked and you hit save, the OneToOne object is deleted, but the main object is kept.
The involved models: one is product, and the other one is extra information for a product if it happens to be a beer:
class Producto(models.Model):
nombre = models.CharField(max_length=100, blank=False)
class Cerveza(models.Model):
producto = models.OneToOneField(Producto)
This is what I've tried to do with the view:
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)
These are my involved forms:
class ProductoForm(ModelForm):
class Meta:
from pdv.models import Producto
model = Producto
class CervezaForm(ModelForm):
class Meta:
from pdv.models import Cerveza
model = Cerveza
And this is how I managed to show both forms in the template:
<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>
But still, the problem is that I cannot add a product if I don't fill out the OneToOne form (Cerveza). So, it can't be empty. Also, if I try to delete the OneToOne form, I get this message:
(Hidden field id) Select a valid choice. That choice is not one of the available choices.
Unfortunately, I haven't been able to find a good example of how to create a form for an optional OneToOneField and use it in a custom template.
I leave you here two examples of how it works in the django admin:
Before adding the optional onetoone object: https://i.sstatic.net/suMEc.png
After creating the optional onetoone object: https://i.sstatic.net/qxNtd.png
I will really appreciate any help. Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您需要更改一件小事情才能使您的代码完美运行。发布表单并保存数据后,您应该重定向到某处,而不是再次显示表单。将:替换
为:(
您可以使用
return redirect('pdv.views.productomodificar', prodcuto.id)
重定向回表单)You need to change one small thing to make your code work perfectly. After POSTing your form and saving your data, you should redirect somewhere instead of showing the form again. Replace:
with:
(You can redirect back to the form with
return redirect('pdv.views.productomodificar', prodcuto.id)
)