Here is my Django forms.py script, using django-crispy-forms
#!/usr/bin/env python
from django import forms
from .models import Method1
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit, Layout
class Method1Form(forms.ModelForm):
def __init__(self, *args, **kwargs):
""" Use for wrapping bootstrap
This is crispy stuff.
"""
super(Method1Form, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_id = 'id-method1Form'
self.helper.form_class = 'form-horizontal'
self.helper.label_class = 'col-lg-2'
self.helper.field_class = 'col-lg-8'
self.helper.form_method = 'post'
self.fields['inputfile_param'].label = "Input File"
self.fields['species_param'].label = "Species"
self.fields['norm_mode_param'].label = "Normalization"
self.fields['logscale_param'].label = "Log Scale"
self.helper.layout = Layout(
'inputfile_param',
'species_param',
'norm_mode_param',
'logscale_param',
)
self.helper.add_input(Submit('submit', 'Submit'))
I can create the following form:
As shown there, I'd like to make the browse button with Bootstrap style.
How can achieve that?
I'm thinking of something like this:
Complete HTML rendered by Django looks like this:
/* Stuff for django-crispy */
.asteriskField {
display: none;
}
.form-control {
font-size:18px;
font-family: "Helvetica Neue",HelveticaNeue;
}
.form-horizontal {
padding-left: 120px;
padding-right: 130px;
font-size:20px;
font-family: "Helvetica Neue",HelveticaNeue;
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<meta charset="utf-8">
</head>
<body>
<!--- DISPLAY THE FORM -->
<form id="id-method1Form" class="form-horizontal" method="post" enctype="multipart/form-data"> <input type='hidden' name='csrfmiddlewaretoken' value='JdUjVaRwOkOxbQmoeSaSHTaDNTlwjs5U' /> <div id="div_id_inputfile_param" class="form-group"> <label for="id_inputfile_param" class="control-label col-lg-2 requiredField">
Input File<span class="asteriskField">*</span> </label> <div class="controls col-lg-8"> <input class="clearablefileinput" id="id_inputfile_param" name="inputfile_param" type="file" /> </div> </div> <div id="div_id_species_param" class="form-group"> <label for="id_species_param" class="control-label col-lg-2 requiredField">
Species<span class="asteriskField">*</span> </label> <div class="controls col-lg-8"> <select class="select form-control" id="id_species_param" name="species_param">
<option value="mouse" selected="selected">Mouse</option>
<option value="human">Human</option>
</select> </div> </div> <div id="div_id_norm_mode_param" class="form-group"> <label for="id_norm_mode_param" class="control-label col-lg-2 requiredField">
Normalization<span class="asteriskField">*</span> </label> <div class="controls col-lg-8"> <select class="select form-control" id="id_norm_mode_param" name="norm_mode_param">
<option value="genecount_norm" selected="selected">Gene Count</option>
<option value="totalscore_norm">Total Score</option>
</select> </div> </div> <div class="form-group"> <div class="controls col-lg-offset-2 col-lg-8"> <div id="div_id_logscale_param" class="checkbox"> <label for="id_logscale_param" class=""> <input class="checkboxinput" id="id_logscale_param" name="logscale_param" type="checkbox" />
Log Scale
</label> </div> </div> </div> <div class="form-group"> <div class="aab controls col-lg-2"></div> <div class="controls col-lg-8"> <input type="submit"
name="submit"
value="Submit"
class="btn btn-primary"
id="submit-id-submit"
/> </div> </div> </form>
<!--- END FORM DISPLAY-->
</body>
</html>
For those that find this, the previous answer does NOT work. The OP is asking for a file input field, not any type of field with a button on it. It seems like Crispy doesn't plan on ever fixing this issue (see issue). Using FieldWithButtons will create an input field with the same default button in addition to a crispy button that says "Go", like this: Go Browse button
The only crispy-centric way to do this is by creating a Browse button template and simply calling template=<your_template>.html when you make the field. I pulled bits from the BaseInput template to make this and it works.
file_input.html
<label for="{% if input.id %}{{ input.id }}{% else %}{{ input.input_type }}-id-{{ input.name|slugify }}{% endif %}" class="btn btn-secondary">
{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}
Browse
<input type="file"
name="{% if input.name|wordcount > 1 %}{{ input.name|slugify }}{% else %}{{ input.name }}{% endif %}"
class="{{ input.field_classes }}"
id="{% if input.id %}{{ input.id }}{% else %}{{ input.input_type }}-id-{{ input.name|slugify }}{% endif %}"
hidden
>
</label>
forms.py
class ProfileUpdateForm(forms.ModelForm):
class Meta:
model = Profile
fields = ['image']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.layout = Layout(
# Fieldset('', *self.fields),
Fieldset('', Button('image', "Browse", css_class="clearablefileinput form-control-file", template="file_input.html", css_id="id_image")),
FormActions(
Submit('save', 'Update Profile'),
)
)
views.py
def profile(request):
p_form = ProfileUpdateForm(request.POST, instance=request.user.profile, files=request.FILES)
#...etc...
Result:
Bootstrappy browse button
I know this is an old post but for any one interested, Crispy Forms has this in the documentation:
FieldWithButtons: You can create an input connected with buttons:
FieldWithButtons('field_name', StrictButton("Go!"))
this is in the docs for crispy forms Bootstrap Layout objects
Related
Created a website with products. I need to make a window for editing them on the site in order to change the manufacturer and other characteristics. This must be done in a pop-up window. I have data displayed, I change it, but nothing changes when I save it. How can this problem be solved.
My vievs:
def parts(request):
added = ''
error = ''
PartAllView = Part.objects.order_by('-id')
if request.method == 'POST' and 'parts_add' in request.POST:
form = PartForm(request.POST, request.FILES)
if form.is_valid():
form.save()
added = 'Добавлено'
else:
error = 'Данная запчасть уже добавлена'
if request.method == 'POST' and 'parts_edit' in request.POST:
PartPost = int(request.POST['parts_edit'])
PartID = Part.objects.get(id=PartPost)
if PartID:
PartID.save()
added = 'Запчасть успешно отредактирована'
else:
error = 'Ошибка редактирования'
form = PartForm()
data = {
'added': added,
'error': error,
'form': form,
'PartAllView': PartAllView,
}
return render(request, 'kross/parts.html', data)
My HTML:
{% if PartAllView %}
{% for el in PartAllView %}
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="modal fade" id="partEdit{{ el.id }}">
<div class="modal-dialog modal-dialog-centered text-center" role="document">
<div class="modal-content modal-content-demo">
<div class="modal-header">
<h6 class="modal-title">Добавление запчасти</h6><button aria-label="Close" class="btn-close"
data-bs-dismiss="modal"><span aria-hidden="true">×</span></button>
</div>
<div class="modal-body">
<div class="row row-sm">
<div class="col-lg-6">
<div class="form-group">
<input type="text" class="form-control" name="brand" value="{{ el.brand }}">
</div>
</div>
<div class="col-lg-6">
<div class="form-group">
<input type="text" class="form-control" value="{{ el.number }}">
</div>
</div>
<div class="col-lg-12">
<div class="form-group">
<input type="text" class="form-control" value="{{ el.name }}"><br>
<input type="textarea" class="form-control" rows="2" value="{{ el.description }}">
</div>
</div>
</div>
{{ el.analog }}
...
You can use updateView to edit an existing data in your website by simply:
from django.views.generic.edit import UpdateView
From MyApp models import #Model
class editview(UpdateView):
model = #Your Model You want to edit
fields = [#Add the fields you want to edit]
template_name = 'edit.html'
success_url = ('Home')
In your edit Template add:
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Update">
I hope it help.
I am building a CRUD app on Django.
I can create, read, and delete just fine, but the update function does not work. I have edited the views.py file (it was a template) to print the error.
Here are the relevant pieces of my code:
#models.py
from django.db import models
class Item(models.Model):
id = models.AutoField(primary_key=True)
etype = models.CharField(max_length=100)
etitle = models.CharField(max_length=100)
eauthor = models.CharField(max_length=100)
estatus = models.CharField(max_length=20)
class Meta:
db_table = "Item"
#views.py
...
def edit(request, id):
item = Item.objects.get(id=id)
return render(request,'edit.html', {'item':item})
def update(request, id):
item = Item.objects.get(id=id)
form = ItemForm(request.POST, instance = item)
print(form.errors)
if form.is_valid():
try:
form.save()
except Exception as e: print(e)
return redirect("/items/show")
return render(request, 'edit.html', {'item': item})
...
I guess the problem has to be in edit.html file, but I cannot figure it out.
#edit.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Index</title>
{% load static %}
<link rel="stylesheet" href="{% static 'css/style.css' %}"/>
</head>
<body>
<form method="POST" class="post-form" action="http://127.0.0.1:8000/items/update/{{item.id}}">
{% csrf_token %}
<div class="container">
<br>
<div class="form-group row">
<label class="col-sm-1 col-form-label"></label>
<div class="col-sm-4">
<h3>Update Details</h3>
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label">Type:</label>
<div class="col-sm-4">
<input type="text" name="etype" id="id_etype" required maxlength="100" value="{{ item.etype }}" />
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label">Title:</label>
<div class="col-sm-4">
<input type="text" name="etitle" id="id_etitle" required maxlength="100" value="{{ item.etitle }}" />
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label">Author:</label>
<div class="col-sm-4">
<input type="text" name="eatuhor" id="id_eauthor" required maxlength="100" value="{{ item.eauthor }}" />
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label">Status:</label>
<div class="col-sm-4">
<input type="text" name="estatus" id="id_estatus" required maxlength="20" value="{{ item.estatus }}" />
</div>
</div>
</div>
<div class="form-group row">
<label class="col-sm-1 col-form-label"></label>
<div class="col-sm-4">
<button type="submit" class="btn btn-success">Update</button>
</div>
</div>
</div>
</form>
</body>
</html>
P.S: I am new to both Django and Software Development, so any kind of feedback is welcome.
I advise you to use UpdateView, its really easier.
Show here Click
Example views.py
class ItemUpdate(UpdateView):
model = Item
template_name = 'edit.html'
Example edit.html:
<form method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Update">
</form>
Thanks for looking into my problem, I am a beginner with Django and Vue your assistance with this wil be extremely helpful. I am working on a Job portal and created the job search functionality in Django as backend for the same I have an app called job into my Django project. The browser Js console gives this error Failed to mount app: mount target selector returned null. For this app I have an add job view, through which an employer adds the jobs. For this I'm using Vue for validation and showing any errors if any non-null fields are not entered by the employer account. So this is not how it was supposed to look,Unexpected results snap shot so as you can see it wasn't supposed to give me [[error]] and company_size instead The company size is missing as per the Vue AddJobApp, given below. Also if were to add # within mount-function-createapp within Vue-AddJobApp, the page entirely disappears (blank page). what am I doing wrong here?
adding # in AddJob.mount() function is making the page go blank a
Add job template
{% extends 'core/base.html' %}
{% block content %}
<div id="add-job-app">
<h1 class="title"> Add Job</h1>
<form action="." method="POST" v-on:submit="validateForm">
{% csrf_token %}
{% if form.errors %}
{% for error in form.errors %}
<div class="notification is-danger">
{{ error }}
</div>
{% endfor %}
{% endif %}
<div class="notification is-danger" v-if ="error.length" >
<p v-for="error in errors" >
[[ error ]]
</p>
</div>
<div class="field">
<label for="">Title</label>
<div class="control">
<input class="input" type="text" name="title" id="id_title" v-model= "title">
</div>
</div>
<div class="field">
<label for="">Short description</label>
<div class="control">
<textarea name="short_description" id="id_short_description" class="textarea" v-model= "short_description" ></textarea>
</div>
</div>
<div class="field">
<label for="">Long description</label>
<div class="control">
<textarea name="long_description" id="id_long_description" class="textarea" v-model= "long_description" ></textarea>
</div>
</div>
<div class="field">
<label for="">Company name</label>
<div class="control">
<input class="input" type="text" name="company_name" id="id_company_name" v-model= "company_name" >
</div>
</div>
<div class="field">
<label for="">Company address</label>
<div class="control">
<input class="input" type="text" name="company_address" id="id_company_address" v-model= "company_address">
</div>
</div>
<div class="field">
<label for="">Company zipcode</label>
<div class="control">
<input class="input" type="text" name="company_zipcode" id="id_company_zipcode" v-model= "company_zipcode">
</div>
</div>
<div class="field">
<label for="">Company place</label>
<div class="control">
<input class="input" type="text" name="company_place" id="id_company_place" v-model= "company_place">
</div>
</div>
<div class="field">
<label for="">Company Country</label>
<div class="control">
<input class="input" type="text" name="company_country" id="id_company_country" v-model= "company_country">
</div>
</div>
<div class="field">
<label for="">Company Size</label>
<div class="control">
<div class="select">
<select name="company_size" v-model = "company_size">
<option value="">Choose Size</option>
<option value="size_1_9">1-9</option>
<option value="size_10_49">10-49</option>
<option value="size_50_99">50-99</option>
<option value="size_100">100+</option>
</select>
</div>
</div>
</div>
<div class="field">
<div class="control">
<button class="button is-success">Submit</button>
</div>
</div>
</form>
</div>
{% endblock %}
{% block scripts %}
<script >
const AddJobApp = {
data() {
return {
title:'',
company_name:'',
short_description:'',
company_size:'',
errors:[]
}
},
delimiters:['[[',']]'],
methods :{
validateForm(e){
this.errors = []
if( this.title ===''){
this.errors.push('The title field is missing')
}
if( this.short_description ===''){
this.errors.push('The short description field is missing')
}
if( this.company_name ===''){
this.errors.push('The company name field is missing')
}
if( this.company_size ===''){
this.errors.push('The company size is missing')
}
if(this.errors.length){
e.preventDefault()
return false
}else{
return true
}
}
}
}
Vue.createApp(AddJobApp).mount('add-job-app');
</script>
{% endblock %}
my views.py file inside of job app
from apps.job.forms import AddJobForm, ApplicationForm
from django.shortcuts import redirect, render
from .models import Job
from django.contrib.auth.decorators import login_required
from apps.notification.utilities import create_notification
def job_detail(request,job_id):
job = Job.objects.get(pk=job_id)
return render(request, 'job/job_detail.html',{'job':job})
def search(request):
return render(request,'job/search.html')
#login_required
def apply_for_job(request,job_id):
job = Job.objects.get(pk=job_id)
if request.method=='POST':
form = ApplicationForm(request.POST)
if form.is_valid():
application = form.save(commit=False)
application.job = job
application.created_by = request.user
application.save()
create_notification(request, job.created_by ,'application',extra_id=application.id)
return redirect('dashboard')
else:
form = ApplicationForm()
return render(request,'job/apply_for_job.html',{'form':form,'job':job})
#login_required
def add_job(request):
if request.method=='POST':
form = AddJobForm(request.POST)
if form.is_valid():
job = form.save(commit=False)
job.created_by = request.user
job.save()
return redirect('dashboard')
else:
form = AddJobForm()
return render(request,'job/add_job.html',{'form':form})
Regist form cannot be sent.
I wrote in views.py
def login(request):
login_form = LoginForm(request.POST)
regist_form = RegisterForm(request.POST)
if login_form.is_valid():
user = login_form.save()
login(request, user)
context = {
'user': request.user,
'login_form': login_form,
'regist_form': regist_form,
}
return redirect('profile')
context = {
'login_form': login_form,
'regist_form': regist_form,
}
return render(request, 'registration/accounts/login.html', context)
in login.html
<body>
<ul class="top-menu">
<h3 class="login">Login</h3>
<div class="container">
<form action="{% url 'login' %}" method="post" role="form">
{% csrf_token %}
<div class="form-group">
<label class="email_form">Email</label>
<input for="id_email" name="email" type="text" value="" placeholder="Email" class="form-control"/>
</div>
<div class="form-group">
<label class="password_form">Password</label>
<input id="id_password" name="password" type="password" value="" minlength="8" maxlength="12" placeholder="Password" class="form-control"/>
</div>
<button type="submit" class="btn btn-primary btn-lg">Login</button>
<input name="next" type="hidden" value="{{ next }}"/>
</form>
</div>
</ul>
<div class="newaccount">
<h2>New Account registration</h2>
<form class="form-inline" action="{% url 'accounts:detail' %}" method="POST">
<div class="form-group">
<label for="id_username">Username</label>
{{ form.username }}
{{ form.username.errors }}
</div>
<div class="form-group">
<label for="id_email">Email</label>
{{ form.email }}
{{ form.email.errors }}
</div>
<div class="form-group">
<label for="id_password">Password</label>
{{ form.password1 }}
{{ form.password1.errors }}
</div>
<div class="form-group">
<label for="id_password">Password(conformation)</label>
{{ form.password2 }}
{{ form.password2.errors }}
<p class="help-block">{{ form.password2.help_text }}</p>
</div>
<button type="submit" class="btn btn-primary btn-lg">Regist</button>
<input name="next" type="hidden"/>
{% csrf_token %}
</form>
</div>
</body>
in forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.forms import AuthenticationForm
from .models import User
class RegisterForm(UserCreationForm):
class Meta:
model = User
fields = ('username', 'email',)
def __init__(self, *args, **kwargs):
super(RegisterForm, self).__init__(*args, **kwargs)
self.fields['username'].widget.attrs['class'] = 'form-control'
self.fields['email'].widget.attrs['class'] = 'form-control'
self.fields['password1'].widget.attrs['class'] = 'form-control'
self.fields['password2'].widget.attrs['class'] = 'form-control'
class LoginForm(AuthenticationForm):
def __init__(self, *args, **kwargs):
super(LoginForm, self).__init__(*args, **kwargs)
self.fields['username'].widget.attrs['class'] = 'form-control'
self.fields['password'].widget.attrs['classF'] = 'form-control'
in urls.py
urlpatterns = [
url(r'^login/$', views.login,name='login'),
]
No error happens in login form ,but in registration form all input field is not shown.I think RegisterForm cannot be sent, but I really cannot understand why all input field of LoginForm is ok although I send LoginForm by using same way of RegisterForm.
How should I fix this?What should I write it?
You're render HTML with login_form and register_form in your form HTML.
But you're trying to render with form var instead of register_form, so django doesn't know what to render.
If you try to render not-exist variable in django template engine, it just show Nothing at all. So there will be NO errors!
Change your HTML code like this:
<body>
<ul class="top-menu">
<h3 class="login">Login</h3>
<div class="container">
<form action="{% url 'login' %}" method="post" role="form">
{% csrf_token %}
<div class="form-group">
<label class="email_form">Email</label>
<input for="id_email" name="email" type="text" value="" placeholder="Email" class="form-control"/>
</div>
<div class="form-group">
<label class="password_form">Password</label>
<input id="id_password" name="password" type="password" value="" minlength="8" maxlength="12"
placeholder="Password" class="form-control"/>
</div>
<button type="submit" class="btn btn-primary btn-lg">Login</button>
<input name="next" type="hidden" value="{{ next }}"/>
</form>
</div>
</ul>
<div class="newaccount">
<h2>New Account registration</h2>
<form class="form-inline" action="{% url 'accounts:detail' %}" method="POST">
<div class="form-group">
<label for="id_username">Username</label>
{{ regist_form.username }}
{{ regist_form.username.errors }}
</div>
<div class="form-group">
<label for="id_email">Email</label>
{{ regist_form.email }}
{{ regist_form.email.errors }}
</div>
<div class="form-group">
<label for="id_password">Password</label>
{{ regist_form.password1 }}
{{ regist_form.password1.errors }}
</div>
<div class="form-group">
<label for="id_password">Password(conformation)</label>
{{ regist_form.password2 }}
{{ regist_form.password2.errors }}
<p class="help-block">{{ regist_form.password2.help_text }}</p>
</div>
<button type="submit" class="btn btn-primary btn-lg">Regist</button>
<input name="next" type="hidden"/>
{% csrf_token %}
</form>
</div>
</body>
This code will show your input tags.
And one thing more... Why don't you use login_form in your HTML?
I am trying to generate a form dynamically and want to assign indentation of form fields. I am trying to assign an custom attribute offset to forms.CharField in subclass. I plan to use this logic to create a form dynamically from an xml file, where the fields would be indented based on the depth of the node.
I am unable to retrieve the value of offset while rendering the template and hence unable to assign the margin-left style parameter. The final html output is also shown.
Can someone please help. I have searched some other answers on this site where it appears that arbitrary attributes can be assigned and retrieved in template. e.g.as in thread here where an arbitrary label_class attribute is assigned
My forms.py file :
class MyCharField(forms.CharField):
def __init__(self, *args, **kwargs):
self.offset = kwargs.pop('offset', 0)
super(MyCharField, self).__init__(*args, **kwargs)
class MyDynamicForm(forms.Form):
def __init__(self, *args, **kwargs):
super(MyDynamicForm, self).__init__(*args, **kwargs)
self.fields["Field_A"] = MyCharField(label="Input A", offset="5")
self.fields["Offset_Field_B"] = MyCharField(label="Input B", offset="50")
My Views.py looks like this:
class MyDynamicView(View):
template_name = 'demo/myform.html'
form_class = MyDynamicForm
def get(self, request, *args, **kwargs):
form = self.form_class()
return render(request, self.template_name, {'form': form})
My template file using bootstrap looks like this:
{% extends 'demo/base.html' %}
{% load bootstrap3 %}
{% block content %}
<form role="form" method="post">
{% csrf_token %}
{% for field in form %}
<div class="form-group bootstrap3-required">
<label class="col-md-3 control-label " style = "margin-left: {{field.offset}}px" for="{{ field.name }}">{{ field.label}}</label>
<div class="col-md-9">
<input class="form-control" id="id_{{field.name}}" name="{{ field.name }}" placeholder="{{field.label}}" style="margin-left:{{field.offset}}px" title="" required="" type="text"/>
</div>
</div>
{% endfor %}
{% buttons submit='OK' reset='Cancel' layout='horizontal' %}{% endbuttons %}
</form>
{% endblock %}
The html output is:
<form role="form" method="post">
<input type='hidden' name='csrfmiddlewaretoken' value='lTy0rc2r9KNiNNPosUoriUlNzYBpgoVpael1MYLOczFECO7H7LXdES6EGBhUoXx0' />
<div class="form-group bootstrap3-required">
<label class="col-md-3 control-label " style = "margin-left: px" for="Field_A">Input A</label>
<div class="col-md-9">
<input class="form-control" id="id_Field_A" name="Field_A" placeholder="Input A" style="margin-left:px" title="" required="" type="text"/>
</div>
</div>
<div class="form-group bootstrap3-required">
<label class="col-md-3 control-label " style = "margin-left: px" for="Offset_Field_B">Input B</label>
<div class="col-md-9">
<input class="form-control" id="id_Offset_Field_B" name="Offset_Field_B" placeholder="Input B" style="margin-left:px" title="" required="" type="text"/>
</div>
</div>
<div class="form-group"><label class="col-md-3 control-label"> </label><div class="col-md-9"><button class="btn btn-default" type="submit">OK</button> <button class="btn btn-default" type="reset">Cancel</button></div></div>
</form>
It not necessary to instantiate from CharField for that. Probably such initialization of the field in form will be enough for you:
field_a = forms.CharField('Input_A',
widget=forms.TextInput(attrs={'placeholder': 'Input_A', 'style': 'margin-left: 50px'}))