So for forms, if you have quantity = IntegerField() in forms.py, then in the html file you can write {{ form.quantity }} to get the input for the quantity. How can do you the samething for modelformset_factory?
I've created a formset to ask the user for the item name and quantity. The item name is given by the loop. I need to move the modelformset factory inside the loop for each iteration, but I don't know how
#views.py
#for showing items
if (Items.objects.filter(item_category="Produce").exists()):
produce = Items.objects.filter(item_category="Produce", show=True, quantity__gte=1)
if (Items.objects.filter(item_category="Grains").exists()):
grains = Items.objects.filter(item_category="Grains", show=True, quantity__gte=1)
if (Items.objects.filter(item_category="Protein/Dairy").exists()):
protein_dairy = Items.objects.filter(item_category="Protein/Dairy", show=True, quantity__gte=1)
if (Items.objects.filter(item_category="extras").exists()):
extras = Items.objects.filter(item_category="extra items", show=True, quantity__gte=1)
#playing with formset
form_extras = Items.objects.filter(show=True).count()
formset = modelformset_factory(Cart, form=CustomerOrderForm,extra=form_extras)
form = formset(queryset=Items.objects.none())
if request.method == 'POST':
form = formset(request.POST)
#work on this
if form.is_valid():
print("is valid")
form = formset(request.POST)
instances = form.save(commit=False)
for instance in instances:
#item previously in cart
if (Cart.objects.filter(username=request.user, item_name=form.cleaned_data.get('item_name')).exists()):
cart_instance = Cart.objects.get(username=request.user, item_name=form.cleaned_data.get('item_name'))
cart_instance.quantity = cart_instance.quantity + form.cleaned_data.get('quantity')
cart_instance.save()
else:
#item never in cart, create new instance
item_instance = Items.objects.get(item_name=form.cleaned_data.get('item_name'))
Cart.objects.create(username=request.user, item_name=form.cleaned_data.get('item_name'), weight=item_instance.weight, quantity=form.cleaned_data.get('quantity'), description=item_instance.description, image=item_instance.image, price=item_instance.price, storage_type=item_instance.storage_type, item_category=item_instance.item_category, limit=item_instance.limit,)
timestamp = datetime.date.today()
messages.success(request,"Sucessfully added your items to your cart! " + str(timestamp))
return redirect('/')
else:
print("form not valid for cart")
form = formset()
user_produce_points = request.user.profile.produce_points
user_grain_points = request.user.profile.grain_points
user_protein_dairy_points = request.user.profile.protein_dairy_points
user_extras_points = request.user.profile.extra_items_points
Home.html:
#home.html
<form method="POST">
{% csrf_token %}
{{ form.management_form }}
{{form.as_p}}
<div class="row">
{% for item in produce %}
<div class="card" style="width: 18rem;">
<img src="/media/{{ item.image }}" class="card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title text-center">
<b>{% if item.storage_type == "Frozen" %}
Frozen
{% endif %}
{{ item.item_name }} ({{ item.weight }} oz)</b></h5>
<h6 class ="card-title text-center" style="color:green;font-size: 16px;"><b>{{ item.price }} Produce
{% if item.price < 2 %}
Point
{% else %}
Points
{% endif %}
</b></h6>
<p class="card-text">{{ item.description }}</p>
<br><br>
<div class="input-quantity">
<input type="hidden" name="form-{{forloop.counter}}-item_name" value="{{ item.item_name }}">
{{form.quantity}}
{{form.item_name}}
{{form.field}}
Quantity: <input style="max-width:3em;" type="number" name="form-{{forloop.counter}}-quantity" pattern="[0-9]{3}" min="0" max="{{ item.limit }}">
</div>
</div>
</div>
{% endfor %}
<br>
<button type="submit" style="height:38px;" class="btn btn-primary btn-lg sharp" type="button">Add to Cart</button>
</form>
Django Docs always has a nice example, it always helps me.
You sadly didn't post (I'm assuming you didn't) the rest of the view function so I can only guess that form in the template refers to the formset created in the view and that is gets passed. And if it does, you would need to first create the for-loop before accessing it in name="form-{{forloop.counter}}-item_name". You could create it like this:
{% for form_line in form %}
<!--form_line rendering you have-->
<p>Form #{{ forloop.counter }}</p>
{{ form_line.quantity }}
{{ form_line.item_name }}
{{ form_line.field }}
{% endfor %}
In your template you also have the produce variable. I am unsure what that refers to, again, maybe because I can't see the whole view function.
Related
I am having difficulty saving a Django model instance into my db. The instance consists of a FileField, which I think is what is causing the difficulty. My model is as follows:
class initial_settings(models.Model):
name = models.CharField(max_length=30, unique=True)
epsilon = models.FloatField(default = 0.3)
document = models.FileField(upload_to='documents/')
def __str__(self):
return self.name
And when I open up a shell, create an instance, and save, I then run the command
test = initial_settings(name = 'test1234', epsilon = 3, document = 'doc.csv').save()
pd.DataFrame(csv.reader(open(test.document.path, 'r')))
Gives me an error, No such file or directory . But, if I open up the admin console and create an instance, it saves correctly and I am able to load it from shell. In the admin console, I can see that the instance created in shell is not being saved to the correct location ('media/documents') but instead direct to root dir, but I am not sure why. Any assistance is appreciated!
P.S:
Settings.py
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')
Edit: adding view and template:
views.py
FORMS_REG = [("doc_step1", Doc_form_1),
("doc_step2", Doc_form_2),
]
TEMPLATES = {"doc_step1": "doc_step_1.html",
"doc_step2": "doc_step_2.html",
}
class Forecast_Wizard(SessionWizardView):
def get_template_names(self):
return [TEMPLATES[self.steps.current]]
instance = None
def get_form_instance( self, step ):
if self.instance is None:
self.instance = initial_settings()
return self.instance
file_storage = FileSystemStorage(location=settings.MEDIA_ROOT)
def done(self, FORMS_REG, **kwargs):
model_name = self.get_cleaned_data_for_step('doc_step2')['name']
self.instance.save()
doc_obj = initial_settings.objects.get(name = name)
return redirect('home')
templates (doc_step1 and doc_step2 use the same template code):
<body>
<div class="container">
<!--Row with two equal columns-->
<div class="row">
<div class="col-lg-1 col-md-1 col-xl-1 col-sm-1">
</div>
<div class="col-lg-4 col-md-4 col-xl-4 col-sm-12">
<br>
<br>
<br>
<br>
<div class="card">
<div class="card-body">
<p class = "card-text">Step {{ wizard.steps.step1 }} of {{ wizard.steps.count }}</p>
{% for field in form %}
{{field.error}}
{% endfor %}
<form action="" method="post">{% csrf_token %}
<table>
{{ wizard.management_form }}
{% if wizard.form.forms %}
{{ wizard.form.management_form }}
{% for form in wizard.form.forms %}
{{ form }}
{% endfor %}
{% else %}
{{ wizard.form }}
{% endif %}
</table>
{% if wizard.steps.prev %}
<button name="wizard_goto_step" class="btn btn-dark" type="submit" value="{{ wizard.steps.first }}">first step</button>
<button name="wizard_goto_step" class="btn btn-dark" type="submit" value="{{ wizard.steps.prev }}">prev step</button>
{% endif %}
<input class="btn btn-dark" type="submit" value="submit"/>
</form>
</div>
</div>
</div>
<div class="col-lg-1 col-md-1 col-xl-1 col-sm-1">
</div>
</div>
</div>
</body>
I figured it out, was a pretty simple error. The form type on my template was wrong. I needed
<form enctype="multipart/form-data" action="" method="post">{% csrf_token %}
instead of just
<form action="" method="post">{% csrf_token %}
I am trying to create a form using django and css.
views.py
from django.shortcuts import render
from .forms import ContactForm
def home(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
pass
else:
form = ContactForm()
return render(request, 'home.html', {'form':form})
forms.py
from django import forms
class ContactForm(forms.Form):
name = forms.CharField(max_length = 30)
email = forms.EmailField(max_length = 254)
message = forms.CharField(max_length = 2000, widget = forms.Textarea(),help_text = "Write Your Message here")
def clean(self):
cleaned_data = super(ContactForm, self).clean()
name = cleaned_data.get('name')
email = cleaned_data.get('email')
message = cleaned_data.get('message')
if not name and not email and not message:
raise forms.ValidationError('You have to write something!')
When I try to add the form to my html page like the following it doesn't show up. Just the button shows up, no form fields -
{% extends 'store/main.html' %}
{% load static %}
{% block content %}
<h3>Store</h3>
<form method = "post" novalidate>
{% csrf_token %}
{{ form }}
<button type='submit'>Submit</button>
</form>
{% endblock content %}
If I do css form instead it obviously show up the way it should.
{% extends 'store/main.html' %}
{% load static %}
{% block content %}
<h3>Store</h3>
<form>
<label for="fname">First Name</label>
<input type="text" id="fname" name="fname">
<button type='submit'>Submit</button>
</form>
{% endblock content %}
So I decided to add the form fields individually to the css form. Where does the {{form.name}} or {{form.email}} tag go?
EDIT:
Hey Vivek, the contact form code is this -
class ContactForm(forms.Form):
name = forms.CharField(max_length = 30)
email = forms.EmailField(max_length = 254)
message = forms.CharField(max_length = 2000, widget = forms.Textarea(),help_text = "Write Your Message here")
The html template looks like this-
{% extends 'store/main.html' %}
{% load static %}
{% block content %}
<h3>Store</h3>
<form method = "post" novalidate>
{% csrf_token %}
<label class="float-left" for="name">Name</label>
{{ form.name }}
<button type='submit'>Submit</button>
</form>
{% endblock content %}
Thanks for any input.
Accessing form fields individually will make you to render the form errors individually as well. {{form}} encapsulates everything:- Form fields , errors, non_field_errors..So if you have to access the fields individually do not forget to add the form errors.
I have written a sample code which will server the purpose.
{% csrf_token %}
{% if form.errors %}
<div class="alert alert-danger" style="text-align:left">
<ul>
{% for field in form %}
{% for error in field.errors %}
<li><strong>{{ error|escape }}</strong></li>
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
<li><strong>{{ error|escape }}</strong></li>
{% endfor %}
</ul>
</div>
{% endif %}
<div class="form-row">
<div class="col-md-4 mb-3">
<label class="float-left" for="id_name">Name</label>
{{ form.name }}
</div>
<div class="col-md-8 mb-3">
<label class="float-left" for="id_email">Email ID</label>
{{ form.email }}
</div>
</div>
<br>
<input type="submit" class="btn btn-primary" value="Pay" id="submit">
</form>
Basically if I tried to use this code
{% for field in form %}
<div class="input">
<label for="" class="labelinput">{{field.label}}</label>
{{field}}
</div>
{% endfor %}
the form data wont make it pass is_valid().But it renders out the form fine. and if I use this code
<form action="" method="post"> {% csrf_token %}
{{form}}
<input type="submit" value="">
it worked perfectly fine. How do I get the first code to work because I want to add classes between the label and the input field
and here's my view
def booklist_view(request):
bkff = BookListForm()
if request.method == 'POST':
bkff = BookListForm(request.POST)
if bkff.is_valid():
bkff.save()
bkff = BookListForm()
context = {
'form': bkff,
}
return render(request, 'booklist1st/booklist.html', context)
Please try this.
views.py
def booklist_view(request):
form = BookListForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
form.save()
context = {'form': form }
return render(request, 'booklist1st/booklist.html', context)
Here we render field according according to field type(hidden_fields,visible_fields).
html template:
<form method="post">
{% csrf_token %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in form.visible_fields %}
<div class="input">
{{field.label}}
{{field}}
</div>
{% endif %}
<input class="btn btn-primary" type="submit" name="add_book" value="Save and add book" />
</form>
You need to specify each field relate data like for=, id=, etc. To have maximum control over how your form is rendered, specify each field and control its style, for example, as we can't see your Form definition, this is an example on how it would be for a title field:
<form method="post">{% csrf_token %}
{# Include the hidden fields #}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{# Include the visible fields #}
{{ form.non_field_errors }}
{{ form.title.errors }}
<label for="{{ form.title.id_for_label }}">Title</label>
{{ form.title }}
{% if form.title.help_text %}
<small id="titleHelp">{{ form.title.help_text|safe }}</small>
{% endif %}
</div>
<input class="btn btn-primary" type="submit" name="add_book" value="Save and add book" />
</form>
<form method="post">
{% csrf_token %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in form.visible_fields %}
<div class="input">
<label for="" class="label">{{field.label}}</label>
{{field}}
</div>
{% endfor %}
<input class="btn btn-primary" type="submit" name="add_book" value="Save and add book" />
</form>
View.py
from django.views.decorators.csrf import csrf_protect
#csrf_protect
def booklist_view(request):
bkff = BookListForm()
if request.method == 'POST':
bkff = BookListForm(request.POST)
if bkff.is_valid():
bkff.save()
context = {
'form': bkff,
}
return render(request, 'booklist1st/booklist.html', context)
my datefields in my django form render always as invalid, but no errors of the how and why are given. (I use both non_field_errors as field.errors )
My Form
class FilterJournalForm(forms.Form):
end_initial = datetime.now(utc)
from_initial = (end_initial - timedelta(days=30))
from_date = forms.DateField(
widget=forms.DateInput(format='%m-%d-%Y'),
initial=from_initial,
required=True,
)
end_date = forms.DateField(
widget=forms.DateInput(format='%m-%d-%Y'),
initial=end_initial,
required=True,
)
part of my view that has the form:
filter_form = FilterJournalForm(request.POST or None)
if request.POST:
print request.POST
if filter_form.is_valid():
print "success"
My template part:
<form class="form-inline" action="" method="POST">
{% csrf_token %}
<div class="form-group">
{{ filter_form.from_date|add_css_class:"form-control input-sm" }}
</div> until
<div class="form-group">
{{ filter_form.end_date|add_css_class:"form-control input-sm" }}
</div>
<button type="submit" class="btn btn-primary btn-sm" >Filter</button>
{% if filter_form.errors %}
<div id="form-error">
<p>The operation could not be performed because one or more error(s) occurred.<br />{{ filter_form.non_field_errors }}</p>
<ul>
{% for field in form %}
<li>{{ field.errors|striptags }}</li>
{% endfor %}
</ul>
</div>
Any idea what is going wrong here? (i also tried to change the initial input of my formfields to date.today() to see if datetime objects could be ruining it. But that as well is not the problem.
{% endif %}
I'm making an application for food recipes and am trying to do the same html in the recipe and include comments in a modal window, the problem is that when I give I submit template fails and does not save the comment on the data base
urls.py
urlpatterns = patterns('recetas.apps.menus.views',
url(r'^recetas/$','recetas_view',name='vista_recetas'),
url(r'^reporte/$','reporte_receta',name='receta_reporte'),
url(r'^receta/(?P<id_receta>\d+)$','detalle_receta', name='vista_detalle'),
)
The html code that calls this url
<td><a href='/receta/{{ receta.id }}'>{{ receta.titulo }}</a></td>
views.py
def detalle_receta(request, id_receta):
dato = get_object_or_404(Receta, pk=id_receta)
comentarios = Comentario.objects.filter(receta=dato)
if request.POST:
if request.POST.get('cancel', id_receta):
return HttpResponseRedirect('/receta/{0}'.format(id_receta))
form = ComentarioForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/receta/{0}'.format(id_receta))
else:
form = ComentarioForm(initial={'receta': id_receta})
cxt = {'receta':dato,'comentarios':comentarios,'form':form}
return render_to_response('menus/receta.html', cxt, context_instance=RequestContext(request))
receta.html
{% extends 'base.html' %}
{% block titulo %}{{ receta.titulo }}{% endblock titulo %}
{% block estatico %}
<link rel='stylesheet' href='{{ STATIC_URL }}css/receta.css' type='text/css'>
<link rel='stylesheet' href='{{ STATIC_URL }}css/modal.css' type='text/css'>
<script type='text/javascript'>
function despliegaModal(valor) {
var elem = document.getElementById("bgVentanaModal");
elem.style.visibility = valor;
}
</script>
{% endblock estatico %}
{% block contenido %}
<div id="bgVentanaModal">
<div id="ventanaModal">
<form action="/receta/{{ receta.id_receta }}" method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Grabar">
<input name="cancel" type="submit" value="Cancelar">
</form>
</div>
</div>
<div id=receta>
<div id="nombre_receta">
<h1>{{receta.titulo|title}}</h1>
<hr>
</div>
<div id='ingredientes'>
<h2>Ingredientes</h2>
<p>{{ receta.ingredientes }}</p>
</div>
<div id='imagen'>
<img src='{{MEDIA_URL}}{{receta.imagen}}' width="480" height="300" >
</div>
<div id='preparacion'>
<h2>PreparaciĆ³n</h2>
<p>{{ receta.preparacion }}</p>
</div>
<div id='comentarios'>
<h2>Comentarios</h2>
{% for item in comentarios %}
<p>{{ item.texto}}</p>
{% empty %}
<p>Sin Comentarios registrados</p>
{% endfor %}
{% if user.is_authenticated %}
Agregue su comentario
{% endif %}
</div>
<div id="pie">
<hr>
<p>Receta Registrada el {{ receta.tiempo_registro|date:'SHORT_DATETIME_FORMAT' }} por {{ receta.usuario }}</p>
</div>
</div>
{% endblock contenido %}
everything works until I give the cancel key, does not validate the POST.
I believe the problem is in your view.py. Specifically in this part:
if request.POST.get('cancel', id_receta):
return HttpResponseRedirect('/receta/{0}'.format(id_receta))
That if will never result in a False value and, hence, your comment will never be saved. This has to do with how the dict.get function works:
get(key[, default])
Return the value for key if key is in the dictionary, else default. If default is not given, it defaults to None, so that this method never raises a KeyError.
So, if you click Grabar you'll get the default value (id_receta). Try the following instead:
if request.POST.get('cancel'): # Default to None
return HttpResponseRedirect('/receta/{0}'.format(id_receta))
A workaround would be just using a button with some JavaScript to redirect when you click Cancelar in your template:
views.py
def detalle_receta(request, id_receta):
dato = get_object_or_404(Receta, pk=id_receta)
comentarios = Comentario.objects.filter(receta=dato)
if request.POST:
# if request.POST.get('cancel', id_receta):
# return HttpResponseRedirect('/receta/{0}'.format(id_receta))
form = ComentarioForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/receta/{0}'.format(id_receta))
else:
form = ComentarioForm(initial={'receta': id_receta})
cxt = {'receta':dato,'comentarios':comentarios,'form':form}
return render_to_response('menus/receta.html', cxt, context_instance=RequestContext(request))
receta.html
...
...
<form action="/receta/{{ receta.id_receta }}" method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Grabar">
<input type="button" value="Cancelar" onclick="window.location.href='/receta/{{ dato.id }}'"/>>
</form>
...
...
Of course, you should use get_absolute_url instead of hardcoding URLs.
Thanks for help me Cesar, your answer help me, but my error is in the variable in receta.html
is {{ receta.id }} and in the button is the same the correct is
<form action="/receta/{{ receta.id }}" method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Grabar"/>
<input type="button" value="Cancelar" onclick="window.location.href='/receta/{{ receta.id }}'"/>
</form>
Thanks for your help and a friend who found the error