This is my view.So I want to keep 2 different HTML forms in same view ,But I am unable to do so beacuse whenever I add 1 form , I get the error of other on being none.
def home(request):
name = None
if request.method == 'POST':
name = request.POST.get('name')
choices = request.POST.get('choices')
subtest = request.POST.get('subtest')
reference = request.POST.get('reference')
unit = request.POST.get('unit')
test = Test()
test.name = name
test.save()
subtest = Subtest()
subtest.test = Test.objects.get(name=choices)
subtest.name = subtest
subtest.unit = unit
subtest.reference_value = reference
subtest.save()
# print(name)
return redirect('home')
return render(request,'main.html',{})
I have got 2 different forms . I didn't use django forms because I wanted to try something new.
MY FIRST FORM
<form method="POST">
{% csrf_token %}
<div class="icon-holder">
<i data-modal-target="test-popup" class="icon-cross"></i>
</div>
<div class="input-group">
<input type="text" name="name" placeholder="Test name" />
</div>
<div class="button-group">
<button type="submit">Submit</button>
</div>
</form>
MY SECOND FORM
<form method="POST">
{% csrf_token %}
<div class="icon-holder">
<i data-modal-target="menu-test-popup" class="icon-cross"></i>
</div>
<div class="input-group">
<label for="test-select">Test Name:</label>
<select name="choices" id="test-select">
{% for test in test %}
<option value="{{test.name}}" name='choices'>{{test.name|title}}</option>
{% endfor %}
</select>
</div>
<div class="input-group">
<input type="text" name="subtest" placeholder="SubTest name" />
</div>
<div class="input-group">
<input type="text" name="reference" placeholder="Reference rate" />
</div>
<div class="input-group">
<input type="text" name="unit" placeholder="Unit" />
</div>
<div class="button-group">
<button type="submit">Submit</button>
</div>
</form>
first form
<form method="POST">
...
<input name="form_type" value="first-form" type="hidden">
</form>
second form
<form method="POST">
...
<input name="form_type" value="second-form" type="hidden">
</form>
view function
def view(request):
if method == "POST":
form_type = request.POST.get('form_type')
if form_type == "first-form":
# first form's process
elif form_type == "second-form":
#second form's process
You have two forms here, when you submit the second form, only the fields from the second form gets submitted.
so from this line
name = request.POST.get('name')
name will become None. But I believe your Test model does not take any None value for name field( the reason for you " IntegrityError at / NOT NULL constraint failed: lab_test.name ").
To overcome this, first check if there is any value for 'name' then proceed with creating the test instance
if name:
test = Test()
test.name = name
test.save()
Similarly check if the other fields are present for the second form before creating and saving the instance.
Related
I have this view with two forms.
def anunciocreateview(request):
anuncio_form = AnuncioForm(request.POST or None)
producto_form = ProductoForm(request.POST or None)
if request.method == "POST":
if all([anuncio_form.is_valid(), producto_form.is_valid(), imagen_form.is_valid()]):
anuncio = anuncio_form.save(commit=False)
anuncio.anunciante = request.user
anuncio.save()
producto = producto_form.save(commit=False)
producto.anuncio = anuncio
producto.save()
return HttpResponse(status=204, headers={'HX-Trigger' : 'eventsListChanged'})
else:
anuncio_form = AnuncioForm()
producto_form = ProductoForm()
context = {
'anuncio_form' : anuncio_form,
'producto_form' : producto_form,
}
return render(request, 'buyandsell/formulario.html', context)
This view works OKAY; it allows the user to create instances of both models with the correct relation. I'm trying to add another form for the image of the product. I tried adding this:
def anunciocreateview(request):
anuncio_form = AnuncioForm(request.POST or None)
producto_form = ProductoForm(request.POST or None)
imagen_form = ImagenForm(request.POST, request.FILES)
if request.method == "POST":
if all([anuncio_form.is_valid(), producto_form.is_valid(), imagen_form.is_valid()]):
anuncio = anuncio_form.save(commit=False)
anuncio.anunciante = request.user
anuncio.save()
producto = producto_form.save(commit=False)
producto.anuncio = anuncio
producto.save()
imagen = imagen_form.request.FILES.get('imagen')
if imagen:
Imagen.objects.create(producto=producto, imagen=imagen)
return HttpResponse(status=204, headers={'HX-Trigger' : 'eventsListChanged'})
else:
print(request.FILES)
else:
anuncio_form = AnuncioForm()
producto_form = ProductoForm()
imagen_form = ImagenForm()
context = {
'anuncio_form' : anuncio_form,
'producto_form' : producto_form,
'imagen_form' : imagen_form
}
return render(request, 'buyandsell/formulario.html', context)
But this happens:
1- The 'Image upload' form field shows error 'This field is required' at the moment of rendering the form.
2- If uploading an image and clicking submit, the redirect doesn't happen as the imagen_form is not marked as valid. No error pops in the console whatsoever (I'm handling requests with HTMX).
If I omit the 'request.FILES' when instantiating the form, the error when the form renders disappear, but it anyway doesn't upload the image nor the form.
What am I missing?
For reference, here is the HTML file:
<form class="row g-3" method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Create new listing</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="mb-3">
<label for="{{ anuncio_form.titulo.auto_id }}">{{ anuncio_form.titulo.label }}</label>
{% render_field anuncio_form.titulo|add_error_class:"is-invalid" class="form-control" %}
</div>
<div class="mb-3">
<label for="{{ anuncio_form.envio.auto_id }}">{{ anuncio_form.envio.label }}</label>
{% translate "Select available delivery options" as input_place_holder %}
{% render_field anuncio_form.envio|add_error_class:"is-invalid" class="form-control" placeholder=input_place_holder %}
</div>
<h5>Product:</h5>
<div class="mb-3">
<label for="{{ producto_form.nombre.auto_id }}">{{ producto_form.nombre.label }}</label>
{% translate "Name of your product" as input_place_holder %}
{% render_field producto_form.nombre|add_error_class:"is-invalid" class=" form-control" placeholder=input_place_holder %}
</div>
<div class="mb-3">
<label for="{{ producto_form.descripcion.auto_id }}">{{ producto_form.descripcion.label }}</label>
{% translate "Give a detailed description of your product" as input_place_holder %}
{% render_field producto_form.descripcion|add_error_class:"is-invalid" class=" form-control" placeholder=input_place_holder %}
</div>
<div class="row g-3">
<div class="col-md-6">
<div class="mb-3">
<label for="{{ producto_form.estado.auto_id }}">{{ producto_form.estado.label }}</label>
{% render_field producto_form.estado|add_error_class:"is-invalid" class=" form-control" %}
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label for="{{ producto_form.cantidad.auto_id }}">{{ producto_form.cantidad.label }}</label>
{% render_field producto_form.cantidad|add_error_class:"is-invalid" class=" form-control" %}
</div>
</div>
</div>
<div class="row g-3">
<div class="col-md-6">
<div class="mb-3">
<label for="{{ producto_form.precio_unitario.auto_id }}">{{ producto_form.precio_unitario.label }}</label>
{% render_field producto_form.precio_unitario|add_error_class:"is-invalid" class=" form-control" %}
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label for="{{ producto_form.disponibilidad.auto_id }}">{{ producto_form.disponibilidad.label }}</label>
{% render_field producto_form.disponibilidad|add_error_class:"is-invalid" class=" form-control" %}
</div>
</div>
</div>
<h5>Images:</h5>
<div class="mb-3">
<label for="{{ imagen_form.imagen.auto_id }}">{{ imagen_form.imagen.label }}</label>
{% render_field imagen_form.imagen|add_error_class:"is-invalid" class=" form-control" %}
</div>
<div id="productforms"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-tertiary" hx-get="{% url 'buyandsell:create-product' %}" hx-target="#productforms" hx-swap="beforeend">Add new product</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-primary" hx-post="{% url 'buyandsell:createview' %}">Submit</button>
</div>
</div>
</form>
Edit:
forms.py for ImagenForm:
class ImagenForm(ModelForm):
class Meta:
model = Imagen
fields = ['imagen']
models.py for the Imagen model:
class Imagen(models.Model):
producto = models.ForeignKey(Producto, on_delete=models.CASCADE, related_name='imagen', blank=True, null=True)
imagen = models.ImageField(upload_to='marketplace/')
def __str__(self):
return f"Imagen de {self.producto}"
def save(self, *args, **kwargs):
self.image = resize_image(self.image, size=(350, 350))
super().save(*args, **kwargs)
Don't initialize forms with request.POST if it is not a POST request.
Two changes to fix your issue:
move first form init block under if request.method == "POST"
move else block one tab to the left so it becomes else to if request.method == "POST" instead of current version where it is else to if .is_valid()
if request.method == "POST":
anuncio_form = AnuncioForm(request.POST or None)
producto_form = ProductoForm(request.POST or None)
imagen_form = ImagenForm(request.POST, request.FILES)
if all([anuncio_form.is_valid(), producto_form.is_valid(), imagen_form.is_valid()]):
...
else:
anuncio_form = AnuncioForm()
producto_form = ProductoForm()
imagen_form = ImagenForm()
Now you use request.POST only on POST requests, instead you show empty forms. If a form is invalid on POST then it will be rendered with errors (if template is done cottectly) instead of showing empty forms back again.
For handling multiple forms with one view/template take a look at these answers: one two three
upd
For HTMX-requests it is also required to set hx-encoding="multipart/form-data" in form element attributes. Similar question HTMX docs
I have been working on a search form and it's giving me this error when i open the url or submit the form.
I am watching a codemy django tutorial and the only thing that is different is that i have some code for pagination i don't know if that's what is affecting it.
base.html
<div class="header-search-wrapper novis_search">
<form method="POST" action="{% url 'listing' %}" name="searchform">
{% csrf_token %}
<div class="custom-form">
<label>Keywords </label>
<input type="text" placeholder="Property Keywords" name="search"/>
<!-- <label >Categories</label>
<select data-placeholder="Categories" name = "home_type" class="chosen-select on-radius no-search-select" >
<option>All Categories</option>
<option>Single-family</option>
<option>Semi-detached</option>
<option>Apartment</option>
<option>Townhomes</option>
<option>Multi-family</option>
<option>Mobile/Manufactured</option>
<option>Condo</option>
</select>
<label style="margin-top:10px;" >Price Range</label>
<div class="price-rage-item fl-wrap">
<input type="text" class="price-range" data-min="10000" data-max="100000000000" name="price-range1" data-step="1" value="1" data-prefix="$₦">
</div> -->
<button type="submit" class="btn float-btn color-bg"><i class="fal fa-search"></i> Search</button>
</div>
</form>
</div>
views.py
def listing(request):
if request.method == 'POST' and 'searchform' in request.POST :
search = request.POST['search']
print(search)
propertys = Property.objects.filter(name__icontains=search)
p = Paginator(Property.objects.order_by('-listed_on'), 2)
page = request.GET.get('page')
propertys = p.get_page(page)
nums = "p" * propertys.paginator.num_pages
return render(request, 'listing.html',{'search_keyword':search,'nums':nums,'propertys':propertys})
else:
p = Paginator(Property.objects.order_by('-listed_on'), 2)
page = request.GET.get('page')
propertys = p.get_page(page)
nums = "p" * propertys.paginator.num_pages
return render(request, 'listing.html',{'propertys':propertys, 'nums':nums})
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.
so no matter what I seem to do I can't get a valid form from just a integer field.
Controller:
def upload_image(request):
if request.method == "POST":
form = AddFloorplan(request.POST, request.FILES)
print request.POST.get('floornumber')
if form.is_valid():
print 'valid'
else:
print(form.errors)
return redirect("/wayfinder/editor/")
Form:
class AddFloorplan(forms.Form):
floor_number = forms.IntegerField(required=True)
Template:
<form action="/wayfinder/addfloorplan/" method="POST" enctype="multipart/form-data"> {% csrf_token %}
<div class="input-field col s12">
<input id="floornumber" autofocus name="floornumber" placeholder="Floor Number" type="text" required>
</div>
<div class="col s12">
<p>
<button class="btn waves-effect waves-light z-depth-0" type="submit" name="action">
<span>Upload</span>
</button>
</p>
</div>
</form>
had no luck passing the values
The name of your form field, floor_number
floor_number = forms.IntegerField(required=True)
does not match the name of your form input, floornumber
<input id="floornumber" autofocus name="floornumber" placeholder="Floor Number" type="text" required>
You need to use the same name in both places.
I have this html search form and I want to link it to my search view to make it work.
<form class="navbar-form navbar-left" role="search" >
<div class="form-group">
<input type="text" class="form-control" placeholder="Search" action = "/search/">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
Here is the views.
def searchResults(request, drname):
# drname = request.GET.get('drname')
doctors = Doctor.objects.filter(name__contains=drname)
clinic = Doctor.objects.filter(clinic__name__contains=drname)
d = getVariables(request)
d['doctors'] = doctors
d['doctors_by_clinic'] = doctors
return render_to_response('meddy1/doclistings.html',d)
urls.py
url(r'^search/(?P<drname>\w+)/$', views.searchResults, name='searchResults'),
Html. <form> must have action attribute, not <input>. Also, send search string as get parameter, don't include it in url (add name attribute to <input>):
<form class="navbar-form navbar-left" role="search" action="/search/">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search" name="drname">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
urls.py. Drop this part (?P<drname>\w+)/:
url(r'^search/$', views.searchResults, name='searchResults'),
views.py. Get search string from GET parameter:
def searchResults(request):
drname = request.GET.get('drname')
doctors = Doctor.objects.filter(name__contains=drname)
clinic = Doctor.objects.filter(clinic__name__contains=drname)
d = getVariables(request)
d['doctors'] = doctors
d['doctors_by_clinic'] = doctors
return render_to_response('meddy1/doclistings.html',d)
action goes in the form element, not the input.