How to imitate django admin's OneToOneField optional form
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: 开发者_StackOverflow社区http://i.imgur.com/p3P6s.png
After creating the optional onetoone object: http://i.imgur.com/UEcm8.png
I will really appreciate any help. Thanks in advance.
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:
alerta = "Producto modificado exitosamente"
with:
from django.shortcuts import redirect
return redirect('my_view')
(You can redirect back to the form with return redirect('pdv.views.productomodificar', prodcuto.id)
)
精彩评论