I am trying not to use formset in my form. Instead of that, I trying to create form dynamically and save all forms data in DB. Currently, I can create a dynamic form, but the thing is I fail to save all data from the form even though I create multiple forms. Now my code only can save only one form. But I want to save the whole form (with multiple form data) in DB.
views.py
def create_order(request):
from django import forms
form = OrderForm()
if request.method == 'POST':
forms = OrderForm(request.POST)
if forms.is_valid():
po_id = forms.cleaned_data['po_id']
supplier = forms.cleaned_data['supplier']
product = forms.cleaned_data['product']
part = forms.cleaned_data['part']
order = Order.objects.create(
po_id=po_id,
supplier=supplier,
product=product,
part=part,
)
return redirect('order-list')
context = {
'form': form
}
return render(request, 'store/addOrder.html', context)
forms.py
class OrderForm(forms.ModelForm):
class Meta:
model = Order
fields = ['supplier', 'product', 'part','po_id']
widgets = {
'supplier': forms.Select(attrs={'class': 'form-control', 'id': 'supplier'}),
'product': forms.Select(attrs={'class': 'form-control', 'id': 'product'}),
'part': forms.Select(attrs={'class': 'form-control', 'id': 'part'}),
}
HTML
<form action="#" method="post" id="form-container" novalidate="novalidate">
{% csrf_token %}
<div class="form">
<div class="form-group">
<label for="po_id" class="control-label mb-1">ID</label>
{{ form.po_id }}
</div>
<div class="form-group">
<label for="supplier" class="control-label mb-1">Supplier</label>
{{ form.supplier }}
</div>
<div class="form-group">
<label for="product" class="control-label mb-1">Product</label>
{{ form.product }}
</div>
<div class="form-group">
<label for="part" class="control-label mb-1">Part Name</label>
{{ form.part }}
</div>
</div>
<button id="add-form" type="button">Add Another Order</button>
<div>
<button id="payment-button" type="submit" class="btn btn-lg btn-success btn-block">
<span id="payment-button-amount">Save</span>
</button>
</div>
</form>
<script>
let poForm = document.querySelectorAll(".form")
let container = document.querySelector("#form-container")
let addButton = document.querySelector("#add-form")
let totalForms = document.querySelector("#id_form-TOTAL_FORMS")
let formNum = poForm.length-1
addButton.addEventListener('click', addForm)
function addForm(e){
e.preventDefault()
let newForm = poForm[0].cloneNode(true)
let formRegex = RegExp(`form-(\\d){1}-`,'g')
formNum++
newForm.innerHTML = newForm.innerHTML.replace(formRegex, `form-${formNum}-`)
container.insertBefore(newForm, addButton)
totalForms.setAttribute('value', `${formNum+1}`)
}
</script>
if request.method == 'POST':
forms = OrderForm(request.POST)
if forms.is_valid():
po_id = forms.cleaned_data['po_id']
supplier = forms.cleaned_data['supplier']
product = forms.cleaned_data['product']
part = forms.cleaned_data['part']
forms.save() # add save here
order = Order.objects.create(
po_id=po_id,
supplier=supplier,
product=product,
part=part,
)
return redirect('order-list')
Related
I am working on the CS50 project2 commerce. I try to create a new list but when I click on the submit button, it doesn´t redirect to the index page as I want. Anybody can help please? I get the error message: auctions.models.Category.DoesNotExist: Category matching query does not exist. However I can add list directly from admin page.
views.py
def createlisting(request):
if request.method == "GET":
allCategories = Category.objects.all()
return render(request, "auctions/create.html", {
"categories": allCategories
})
else:
# get the data from the form
title = request.POST["title"]
description = request.POST["description"]
imageurl = request.POST["imageurl"]
price = request.POST["price"]
category = request.POST["category"]
currentuser = request.user
# get the contents
categoryData = Category.objects.get(categoryName=category)
#create new list object
newListing = Listing(
title=title,
description=description,
imageUrl=imageurl,
price=float(price),
category=categoryData,
owner=currentuser
)
newListing.save()
return HttpResponseRedirect(reverse("index"))
create.html
{% extends "auctions/layout.html" %}
{% block body %}
<h2>Create New Listing</h2>
<form action = "{% url 'create' %}" method="POST">
{% csrf_token %}
<div class="form-group">
<label for="title">Title</label>
<input type="text" name="title" class="form-control" id="title" placeholder="Enter title">
</div>
<div class="form-group">
<label for="description">Description</label>
<input type="text" name="description" class="form-control" id="description" placeholder="Enter Description">
</div>
<div class="form-group">
<label for="imageurl">Image URL</label>
<input type="text" name="imageurl" class="form-control" id="imageurl" placeholder="Image Url">
</div>
<div class="form-group">
<label for="price">Price</label>
<input type="number" name="price" class="form-control" id="price" placeholder="Price">
</div>
<div class="form-group">
<label for="category">Choose a Category</label>
<select name="category" id="category">
{% for category in categories %}
<option value="category">{{category}}</option>
{% endfor %}
</select>
</div>
<button type="submit" class="btn btn-success">Create New Listing</button>
</form>
{% endblock %}
Use redirect. And you don't need to use else after returning in the if statement.
from django.shortcuts import redirect
def createlisting(request):
if request.method == "GET":
allCategories = Category.objects.all()
return render(request, "auctions/create.html", {
"categories": allCategories
})
# POST
title = request.POST["title"]
description = request.POST["description"]
imageurl = request.POST["imageurl"]
price = request.POST["price"]
category = request.POST["category"]
currentuser = request.user
# get the contents
categoryData = Category.objects.get(categoryName=category)
#create new list object
newListing = Listing(
title=title,
description=description,
imageUrl=imageurl,
price=float(price),
category=categoryData,
owner=currentuser
)
newListing.save()
return redirect("index")
Try this view:
def createlisting(request):
allCategories=""
if request.method == "GET":
allCategories = Category.objects.all()
else:
# get the data from the form
title = request.POST["title"]
description = request.POST["description"]
imageurl = request.POST["imageurl"]
price = request.POST["price"]
category = request.POST["category"]
currentuser = request.user
# get the contents
categoryData = Category.objects.get(categoryName=category)
#create new list object
newListing = Listing(
title=title,
description=description,
imageUrl=imageurl,
price=float(price),
category=categoryData,
owner=currentuser
)
newListing.save()
return redirect("index")
return render(request, "auctions/create.html", {
"categories": allCategories
})
I am trying to save po_id as a unique key of the "Order table". So I am generating a random number in the Order Form. But the issue is that somehow I can not save the form, even though all the fields are filled up.
models.py
def random_string():
return str(random.randint(10000, 99999))
class Order(models.Model):
po_id = models.CharField(max_length=4, default = random_string)
supplier = models.ForeignKey(Supplier, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
forms.py
class OrderForm(forms.ModelForm):
class Meta:
model = Order
fields = ['supplier', 'product', 'po_id']
widgets = {
'supplier': forms.Select(attrs={'class': 'form-control', 'id': 'supplier'}),
'product': forms.Select(attrs={'class': 'form-control', 'id': 'product'}),
}
views.py
def create_order(request):
from django import forms
form = OrderForm()
if request.method == 'POST':
forms = OrderForm(request.POST)
if forms.is_valid():
po_id = forms.cleaned_data['po_id']
supplier = forms.cleaned_data['supplier']
product = forms.cleaned_data['product']
order = Order.objects.create(
po_id=po_id,
supplier=supplier,
product=product,
)
return redirect('order-list')
context = {
'form': form
}
return render(request, 'store/addOrder.html', context)
Order.html
<form action="#" method="post" novalidate="novalidate">
{% csrf_token %}
<div class="form-group">
<label for="po_id" class="control-label mb-1">ID</label>
{{ form.po_id }}
</div>
<div class="form-group">
<label for="supplier" class="control-label mb-1">Supplier</label>
{{ form.supplier }}
</div>
<div class="form-group">
<label for="product" class="control-label mb-1">Product</label>
{{ form.product }}
</div>
<div>
<button id="payment-button" type="submit" class="btn btn-lg btn-success btn-block">
<span id="payment-button-amount">Save</span>
</button>
</div>
Can help me with how I can solve the issue?
I'm new in django and i'm stuck now.
I'm trying to pass the url in form [action] attribute that would go to my edit function defined in [views.py] file and do it's job but whenever I try to pass the url [NoReverseMatch] is shown.
This is what i tried to do:
<div class="modal fade" id="editform" role="dialog">
<div class="modal-dialog">
<div class = "modal-content">
<div class = "modal-header">
<button type = "button" class = "close" data-dismiss="modal">×</button>
<h3 class="modal-title">
<b>Edit Information</b>
</h3>
</div>
<div class = "modal-body">
<form action="{% url 'studentapp:editrow' rowid=id %}" id="editform" method="POST">
{% csrf_token %}
<div class = "form-group">
<label for = "your_name">
Your name:
</label>
<input class = "form-control" id="new_name" type = "text" name="name" value="{{ student_detail.name }}" placeholder="Enter your name">
</div>
<div class="form-group">
<label for = "course_name">
Course:
</label>
<input id="new_course" class = 'form-control' type = "text" name="course" value="{{ student_detail.course }}" placeholder="Enter your course">
</div>
<div class = "form-group">
<label for = "rollno">
Roll No.:
</label>
<input id="new_rollno" type = "text" class = 'form-control' name="roll" value="{{ student_detail.roll }}" placeholder="Enter your roll number">
</div>
<div class = "form-group">
<label for ="addr">
Address:
</label>
<input id="new_address" type = "text" name="address" class = 'form-control' value="{{ student_detail.address }}" placeholder="Enter your address"/>
</div>
<input type = "submit" value="Update" id="update" class = "btn btn-success" style="font-size:18px;" />
</form>
</div>
</div>
</div>
</div>
In my urls.py I've used the following url:
url(r'^editrow/(?P<rowid>[0-9]+)/$', views.editrow, name='editrow'),
My [editrow] view looks something like this:
def editrow(request, rowid):
item = get_object_or_404(Studentapp, rowid=id)
print item
if request.method=="POST":
form = EntryForm(request.POST, instance=item)
if form.is_valid():
post=form.save(commit=False)
post.save()
return HttpResponseRedirect(reverse('studentapp:index'),rowid.id)
else:
form=EntryForm(instance=item)
return render(request, 'index.html',{'form':form})
else:
form=EntryForm(instance=item)
return render(request, 'index.html',{'form':form})
View that render's the template:
def index(request):
context = {}
latest_student = Studentapp.objects.order_by('pub_date')
context.update({
'latest_student': latest_student
})
response = {"status": False, "errors": []}
if request.is_ajax():
id = request.POST['id']
response = {}
response['status'] = False
student_detail = Studentapp.objects.filter(id=id).first()
context = {
"student_detail": student_detail
}
template = render_to_string("studentapp/_edit_student.html", context)
response['template'] = template
response['status'] = True
return HttpResponse(json.dumps(response), content_type="applicaton/json")
return render(request, "studentapp/index.html", context)
What i'm doing in crud is:
1) make an [edit] button in table through for loop.
2) when i click [edit] button a pre-populated form shows up(which i'm getting).
3) After i click the pre-populated form i want to edit that form and save it and updated data is reflected in my django db.
Thanks to #Alasdair, I looked in my code what he was trying to tell me and i got the answer.
The url that i was trying to pass through my action attribute was wrong. Here's what i did.
<form action="{% url 'studentapp:editrow' rowid=student_detail.id %}" id="editform" method="POST">
Through "student_detail" i'm able to get pre-populated form as i mentioned above. i used the same to get the id and pass it to my "editrow" view.
It's working for me now.
It seems like you never add id to your context in your view index. So the template does not have that variable available.
You need to add that id to your context.
Just like #Alasdair pointed out in the comments.
I am working with two different forms that loads info from two different models. One form is disabled to edit and the second form is enabled.
Everything is right until I use UpdateView, when I try to make changes on the enable to edit form nothing happens. I am new in Django and found the code on a tutorial and adapted it to my project.
Why UpdateView is not saving changes?
models.py:
class Sitioproyecto(models.Model):
.
.
def __str__(self):
return self.nombre_del_sitio
class Sitiocontratado(models.Model):
sitioproyecto = models.ForeignKey(Sitioproyecto, on_delete=models.CASCADE)
.
.
def __str__(self):
return self.sitioproyecto.nombre_del_sitio
forms.py:
class SitioContratadoForm(forms.ModelForm):
class Meta:
model = Sitiocontratado
exclude = ['slug',]
widgets = {
'fecha_de_contratacion' : forms.DateInput(attrs={
'type' : 'date',
'class' : "form-control pull-right",
'id' : "fechadecon",
}),
'sitioproyecto' : forms.Select(attrs={
'type' : 'text',
'class' : "form-control",
'id' : 'nombresitio',
}),
.
.
}
views.py:
class CrearSitiosContratadosView(CreateView):
model = Sitiocontratado
template_name = 'sitios/contratados/editar_contratado.html'
form_class = SitioContratadoForm
success_url = reverse_lazy('pagina:tabla_contratados')
class UpdateSitiosContratadosView(UpdateView):
model = Sitiocontratado
second_model = Sitioproyecto
template_name = 'sitios/contratados/editar_contratado.html'
form_class = SitioContratadoForm
second_form_class = SitioProyectoForm
success_url = reverse_lazy('pagina:tabla_contratados')
def get_context_data(self, **kwargs):
context = super(UpdateSitiosContratadosView, self).get_context_data(**kwargs)
pk = self.kwargs.get('pk', 0)
sitiocontratado = self.model.objects.get(id=pk)
sitioproyecto = self.second_model.objects.get(id=sitiocontratado.sitioproyecto_id)
if 'form' not in context:
context['form'] = self.form_class()
if 'form2' not in context:
context['form2'] = self.second_form_class(instance=sitioproyecto)
context['id'] = pk
return context
def post(self, request, *args, **kwargs):
self.object = self.get_object
id_sitiocontratado = kwargs['pk']
sitiocontratado = self.model.objects.get(id=id_sitiocontratado)
sitioproyecto = self.second_model.objects.get(id=sitiocontratado.sitioproyecto_id)
form = self.form_class(request.POST, instance=sitiocontratado)
form2 = self.second_form_class(request.POST, instance=sitioproyecto)
if form.is_valid() and form2.is_valid():
form.save()
form2.save()
return HttpResponseRedirect(self.get_success_url())
else:
return self.render_to_response(self.get_context_data(form=form, form2=form2))
template:
{% block content %}
<form class="form-vertical" method="POST">
{% csrf_token %}
<div class="box box-primary">
<div class="box-header with-border">
<h3 class="box-title">Agregar Sitio</h3>
</div>
<div class="box-body">
<div class="row justify-content-start">
<fieldset class="col-md-3 form-group" disabled>
<label for="fechadeval" class="control-label">Fecha de Validación</label>
{{ form2.fecha_de_validacion }}
</fieldset>
<div class="col-md-3 form-group">
<label for="fechadecon" class="control-label">Fecha de Contratación</label>
{{ form.fecha_de_contratacion }}
</div>
</div>
<div class="row justify-content-start">
<fieldset class="col-md-8 form-group" disabled>
<label for="fechadecon" class="control-label">Nombre del Sitio</label>
{{ form.sitioproyecto }}
</fieldset>
<fieldset class="col-md-2 form-group" disabled>
<label for="estatus" class="control-label">ID del Sitio</label>
{{ form2.id_sitio }}
</fieldset>
<fieldset class="col-md-1 form-group" disabled>
<label for="estatus" class="control-label">Candidato</label>
{{ form2.candidato }}
</fieldset>
.
.
</div>
<div class="box-footer">
<a class="btn btn-default" href="{% url 'pagina:tabla_contratados' %}">Regresar</a>
<button type="submit" value="Update" class="btn btn-primary">Guardar</button>
</div>
</div>
</form>
{% endblock %}
In get_context() and post() replace-
context['form2'] = self.second_form_class(instance=sitioproyecto)
with
context['form2'] = self.second_form_class(instance=request.Sitiocontratado.sitioproyecto)
and simply save it!! that's it
you don't need to deal with pk
I am trying to create a ModelForm that links to an external database, and when you submit the form the external database gets updated. The problem comes when I check the validity of the form, it is invalid.
I have done some researching into this and found the most common problem was that the form is not bound, but when I use print(form.non_field_errors) I get:
<bound method BaseForm.non_field_errors of <EmailForm bound=True, valid=False, fields=(subject;body;name;altsubject;utm_source;utm_content;utm_campaign)>
models.py:
class MarketingEmails(models.Model):
messageid = models.AutoField(db_column='column1', primary_key=True)
subject = models.CharField(db_column='column2', max_length=2000)
body = models.TextField(db_column='column3') #using a text field as there is no maximum length
name = models.CharField(db_column='column4', max_length=25)
altsubject = models.CharField(db_column='column5', max_length=2000)
utm_source = models.CharField(db_column='column6', max_length=25)
utm_content = models.CharField(db_column='column7', max_length=25)
utm_campaign = models.CharField(db_column='column8', max_length=25)
class Meta:
managed = False
db_table = ''
forms.py:
class EmailForm(forms.ModelForm):
class Meta:
model = MarketingEmails
fields = ['messageid','subject','body','name','altsubject','utm_source','utm_content','utm_campaign']
views.py:
def emailinfo(request, pk):
if request.session.has_key('shortname'):
shortname = request.session['shortname']
rows = get_object_or_404(MarketingEmails, pk=pk)
if request.method == 'POST':
form = EmailForm(request.POST)
print(form.errors)
print(form.non_field_errors)
if form.is_valid():
form.save()
print("form is valid")
return redirect('marketingemails:emailinfo', pk = rows.messageid)
return render(request, 'marketingemails/emailinfo.html',{'shortname': shortname, 'rows': rows})
else:
return HttpResponseRedirect(reverse('common:login'))
urls.py:
app_name = 'marketingemails'
urlpatterns = [
url(r'^marketing/emails/(?P<pk>[0-9]+)/$', marketingviews.emailinfo, name='emailinfo'),
]
html:
<form method="POST" class="post-form" action ="">
{% csrf_token %}
<label for="exampleTextarea">Name</label>
<textarea class="form-control" id="exampleTextarea" rows="1">{{ rows.name }}</textarea>
<label for="exampleTextarea">Subject</label>
<textarea class="form-control" id="exampleTextarea" rows="1">{{ rows.subject }}</textarea>
<label for="exampleTextarea">Alternative Subject</label>
<textarea class="form-control" id="exampleTextarea" rows="1">{{ rows.altsubject }}</textarea>
<label for="exampleTextarea">Body</label>
<div class="ibox-content no-padding">
<div class="summernote">
{{ rows.body }}
</div>
</div>
<label for="exampleTextarea">utm_source</label>
<textarea class="form-control" id="exampleTextarea" rows="1">{{ rows.utm_source }}</textarea>
<label for="exampleTextarea">utm_content</label>
<textarea class="form-control" id="exampleTextarea" rows="1">{{ rows.utm_content }}</textarea>
<label for="exampleTextarea">utm_campaign</label>
<textarea class="form-control" id="exampleTextarea" rows="1">{{ rows.utm_campaign }}</textarea>
<button type="submit" class="save btn btn-default">Save</button>
</form>
Your HTML form doesn't name the fields so the form can't get them. You want to use the form for rendering too : https://docs.djangoproject.com/en/1.11/topics/forms/#working-with-form-templates