add text field on button click and pack into jsonfield with django - django

I have a jsonfield in my django project and i was wondering how i can have button to add textfields
for example:
i have a list of steps and i want to click a button to add a step (simillarly to adding attachments in email) and then i want to pack all of these into a jsonfield
so my two questions are
how do i add a text field via button and how do i pack the text fields together into a jsonfield
thanks a lot no code is included because i don't think it is necessary
katie
edit: added code:
here is thew view where I create a new recipe object for my cookbook. this is also the view that handles the form that would contain the jsonfields:
def createrecipe(request):
if request.method == 'POST':
form = RecipeForm(request.POST)
if form.is_valid():
form = RecipeForm(initial = {'original_cookbook' : request.user.cookbooks.all()[0]})
form = form.save()
t = loader.get_template('cookbook/create_form.html')
c = RequestContext(request, {
'form': form,
})
data = {
'replace': True,
'form': t.render(c),
'success': True,
}
json = simplejson.dumps(data)
return HttpResponse(json, mimetype='text/plain')
else:
form = RecipeForm(request.POST)
t = loader.get_template('cookbook/create_form.html')
c = RequestContext(request, {
'form':form,
})
data ={
'form': t.render(c),
'success': False,
}
json = simplejson.dumps(data)
return HttpResponse(json, mimetype='text/plain')
here is the model.py for my recipe (where the jsonfields are located):
class Recipe(models.Model):
def __unicode__(self):
return self.name
original_cookbook = models.ForeignKey(Cookbook)
name = models.CharField(max_length=200)
author = models.CharField(max_length= 100)
picture = models.ImageField(upload_to = 'Downloads', blank=True)
pub_date = models.DateTimeField('date published', auto_now_add=True, blank=True)
type = models.CharField(max_length = 2, choices=TYPE_CHOICES)
ingredients = JSONField()
steps = JSONField()
prep_time = models.IntegerField()
here is my account view:
def account(request):
user = request.user
if request.user.is_authenticated():
cookbooks = user.cookbooks
if cookbooks.all().exists():
cookbook = cookbooks.all()[0]
form = RecipeForm(initial = {'original_cookbook' : request.user.cookbooks.all()[0]})
recipe_list = cookbook.recipes.all()
else:
raise Http404
else:
return HttpResponseRedirect('/accounts/login')
t = loader.get_template('cookbook/account.html')
c = RequestContext(request, {
'form': form,
'recipe_list': recipe_list
})
return HttpResponse(t.render(c))
this is the template for the form:
create_form.html the action of the form points to the create recipe view
<body>
<form action="{% url cookbook.views.createrecipe %}" method="POST" name="recipeform" id="createrecipeform">
<table>
{% csrf_token %}
{{ form.as_table }}
</table>
<p><input type="submit" value="Submit"></p>
</form>
<form class="task-form" action="." method="POST">
<button class=".task-add-button" value="Add Task">
{% csrf_token %}
{{ TaskFormSet.as_p }}
</form>
</body>
here is the template for the account page that handles the create_recipe page...
account.html
{% extends "cookbook/base.html" %}
{% load pagination_tags %}
{% load comments %}
<h1>{{ user }}'s Cookbook</h1>
<ul>
{% block nav-cookbooks %}
<li><a class="nav-inactive" href="/cookbooks/">Cookbooks</a></li>
{% endblock %}
{% block nav-account %}
<li><a class="nav-active" href="/account/">My Cookbook</a></li>
{% endblock %}
</ul>
{% block content %}
{% autopaginate recipe_list 6 %}
<div id="recipe_cont">
{% for recipe in recipe_list %}
<div class="recipe">
<div class="button">
<img src="{{ STATIC_URL }}chicknbraw.jpg" alt="" height="70" width="70" style="display:inline;" />
<h4>{{ recipe.name }}</h4>
</div>
<h5>{{ recipe.author }}</h5>
<h5>Prep Time: {{ recipe.prep_time }} minutes</h5>
<h6>Add Recipe
Remove Recipe</h6>
</div>
{% endfor %}
</div>
<div id="popupContact" class="popup">
<a id="popupContactClose" style="cursor:pointer;float:right;">x</a>
<p id="contactArea">
<h1 style="text-align:center">Create New Recipe</h1>
{% include 'cookbook/create_form.html' %}
</p>
</div>
<div id="backgroundPopup">
</div>
<div id="col2-footer">
{% paginate %}
<p id="recipe_order_text"> order by: abc|date
</div>
{% endblock %}
{% block footer %}
<a class="create" style="cursor:pointer" >Create New Recipe</a>
{% endblock %}
base.html:
{% load i18n %}
{% block doctype %}<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
{% endblock %}
{% block head %}
<head>
<title>{% block title %}Recipeek{% endblock %}</title>
<script type="text/javascript">
$(document).ready(function(){
var form = $('form#createrecipeform');
form.submit(function(e) {
e.preventDefault();
console.log('ajax form submission function called successfully.');
//form = $(this);
console.log(form)
var serialized_form = form.serialize();
$.ajax({ type: "POST", 
url: $(this).attr('action'),
data: serialized_form, 
success: (function(data) { 
console.log('ajax success function called successfully.');
data = $.parseJSON(data);
if (data.success) {
console.log('success');
var newForm = data.form;
form.replaceWith(newForm);
} else {
console.log('failure');
var newForm = data.form;
form.replaceWith(newForm);
}
})
});
return false;
});
});
</script>
</head>
{% endblock %}
{% block body %}
<body>
{% block header %}
<div id="header"></div>
{% endblock %}
<div id="left_pane">
<div id="left_pane-container">
<div id="logo"><img src= "/static/recipeek_logo.png" style="padding-left:10px;" /></div>
<div id="left_pane-items">
<div id="nav_out">
<ul id="nav_outlist">
<li>about us</li>
<li>contact</li>
<li>glossary</li>
</ul>
</div><!--nav_out-->
</div><!--left_pane-items-->
</div><!--left_pane-container-->
</div><!--left_pane-->
{% block container %}
<div id="container">
<div id="container_header">
<div id="horz_nav">
<ol>
<li id="cookbook_link">{% block nav-cookbooks %}Cookbooks {% endblock %}</li>
<li id="account_link">{% block nav-account %}My Cookbook{% endblock %}</li>
</ol>
</div>
<div id="container_header-items">
{% trans "Home" %} |
{% if user.is_authenticated %}
{{ user.username }}
({% trans "Log out" %} |
{% trans "Change password" %})
<form action="/search/" method="get">
<input type="text" name="q" id="id_q" value="Search" onfocus="if(this.value==this.defaultValue)this.value='';" onblur="if(this.value=='')this.value=this.defaultValue;"/>
</form>
{% else %}
{% trans "Log in" %}
{% endif %}
</div><!--header-items-->
</div><!--header-->
<div id="col2">
<div id="col2-header"></div>
{% block content %}{% endblock %}
</div>
<div id="footer">
{% block footer %}
{% endblock %}
</div>
</div>
{% endblock %}
</body>
{% endblock %}
</html>
i think that is all of the relevant code.
i think i should also mention I am using ajax to submit the form - im not sure this will make any difference in how to implement this idea. thanks again for the help tom :)

Well katie, what you're going to want to do is set up some javascript on the frontend.
<form class="task-form" action="." method="POST">
<button class=".task-add-button" value="Add Task">
{{ TaskFormSet.as_p }}
</form>
<script>
var $form = $('.task-form')
, $button = $form.find('.task-add-button')
, template = '{{ TaskFormSet.empty_form.as_p }}'
, num_formsets = $form.find('input[name=TOTAL_FORMS]').val();
$button.on('click', function(){
var formset_html = template.replace('__prefix__', 'form-'+(++num_formsets);
$(formset_html).appendTo($form); // Creates new input
return false;
});
</script>
Then you will want a form that will be able to process this list.
https://docs.djangoproject.com/en/dev/topics/forms/formsets/
from django.forms.formsets import formset_factory
class TaskForm(Form):
title = CharField()
... any number of extra fields
TaskFormSet = formset_factory(TaskForm, can_order=True, can_delete=True, extra=1)
# In your view
instance = TaskModel.objects.get(...)
tasks_formset = TaskFormSet(request.POST, initial=instance.tasks_json)
context['TaskFormSet'] = tasks_formset
if request.method == 'POST' and tasks_formset.is_valid():
instance.tasks_json = [task.cleaned_data for task in tasks_formset]
instance.save()
I Hope this helps you, and welcome to StackOverflow!

Related

GCBV Generic Class Based View, Django Classes Issue

$ Hello, I was trying to use "GCBV Generic Class Based View" for edit a post, but it seems not working and event it django can't find my HTML and I don't know why , Hope I get some support ….
$ edit button link
{% if post.created_by == user %}
<div class="mt-3">
<a class="btn btn-success float-end"
href="{% url 'edit_post' post.topic.board.pk post.topic.pk post.pk %}">Edit</a>
</div>
{% endif %}
$ edit HTML Page
{% extends 'base.html' %}
{% load static %}
{% block title %}Edit Post{% endblock %}<!-- | Page-title-->
{% block content %}
<link rel="stylesheet" href="{% static 'css/boards.css' %}">
<div class="newtopic">
<div class="container container-newtopic w-50">
<h1>Edit Post</h1>
<br>
{% include 'parts/alerts.html' %}
<div aria-label="breadcrumb">
<ol class="breadcrumb n1-head">
<li class="breadcrumb-item">Boards</li>
<li class="breadcrumb-item"><a href="{% url 'topics' post.topic.board.pk
%}">
{{post.topic.board.name}}</a></li>
<li class="breadcrumb-item active" aria-current="page"><a href="">Edit
Post</a></li>
</ol>
</div>
<form method="POST" action="" novalidate class="mb-4">
{% csrf_token %}
{% include 'includes/form.html' %}
<button type="submit" class="btn main-btn w-100 rounded-pill mt-5">
Save Changes
</button>
</form>
</div>
</div>
{% endblock %}
$ Views.py
#method_decorator(login_required, name='dispatch')
class PostUpdateView(UpdateView):
model = Post
fields = ('message',)
template_name = 'edit_post.html'
pk_url_kwarg = 'post_id'
context_object_name = 'post'
def form_valid(self, form):
post = form.save(commit=False)
post.updated_by = self.request.user
post.updated_date = timezone.now()
post.save()
return redirect('topic_posts', board_id=post.topic.board.pk, topic_id=post.topic.pk)
$ Urls.py
urlpatterns = [
path('<int:board_id>/topics/<int:topic_id>/posts/<int:post_id>/edit',
views.PostUpdateView.as_view(), name="edit_post"),
]
$error message
TemplateDoesNotExist at /boards/4/topics/24/posts/28/edit
edit_post.html
Request Method: GET
Request URL: http://localhost:8000/boards/4/topics/24/posts/28/edit
Django Version: 4.0.5
Exception Type: TemplateDoesNotExist
Exception Value: edit_post.html

How to show django form in django template?

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>

Django Nested inline formset-- nested form does not save to DB, no errors thrown

We have a few nested inline formsets in an application. Ideally, the goal is to allow for dynamic and unlimited population of these fields so that users can add an arbitrary number of notes. The form renders, the JS calls are populating; however, I am not seeing the update on the nested from manager.
This is my first Django project and I am not finding anything regarding what is causing the hang up. The Organization is saved in the DB, but the notes are not.
Thanks in advance for any help
Model.py:
class Organization(models.Model):
//irrelevant organization information//
class OrganizationNote(AbstractNotes):
note = models.TextField(blank=True)
org = models.ForeignKey(Organization, on_delete=models.CASCADE,blank=True, null=True)
modelforms.py:
class OrganizationForm(AbstractBigThree):
class Meta:
model = custModels.Organization
fields = '__all__'
orgNoteFormSet = inlineformset_factory(custModels.Organization, custModels.OrganizationNote,
form=OrganizationForm, extra=0)
ModelView.py
class OrganizationCreateView(CreateView, AbstractOrganizationView):
def get(self, request, *args, **kwargs):
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
org_note_form = orgNoteFormSet()
return self.render_to_response(
self.get_context_data(form=form,
org_note_form=org_note_form))
def get_context_data(self, **kwargs):
data = super(OrganizationCreateView, self).get_context_data(**kwargs)
if self.request.POST:
data['notes'] = orgNoteFormSet(self.request.POST)
else:
data['notes'] = orgNoteFormSet()
return data
def form_valid(self, form):
context = self.get_context_data()
notes = context['notes']
with transaction.atomic():
self.object = form.save()
if notes.is_valid():
notes.instance = self.object
notes.save()
return super(OrganizationCreateView, self).form_valid(form)
def get_success_url(self):
return '/portal'
template:
{% extends 'base.html' %}
{% load i18n widget_tweaks %}
{% block __file__ %}
<!-- filename == organization_create_form.html -->
{% endblock %}
{% block container %}
<script type="text/javascript">
$(function() {
$(".inline.{{ org_note_form.prefix }}").formset({
prefix: "{{ org_note_form.prefix }}",
})
})
</script>
<div class="content">
<div class="thermometer">
<div style="float:left;padding:10px;">
Dashboard
</div>
<div style="float:left;padding:10px;">
>><a class="back-link" style="padding-left:10px;"href="">Organization List</a>
</div>
</div>
<div class="col-md-7 main">
<h1>Create Organization</h1>
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endfor %}
<div id = "form_set">
<legend>Notes</legend>
</div>
<input type="button" value="Add Note" id="add_more">
<div id="form_set">
{{ org_note_form.management_form }}
{{ org_note_form.non_form_errors}}
{% for form in org_note_form.forms %}
{{form.non_field_errors}}
{{form.errors}}
<table class='no_error'>
{{ form }}
</table>
{% endfor %}
</div>
<div id="empty_form" style="display:none">
<table class='no_error'>
<fieldset>
{{ org_note_form.empty_form}}
<div class="inline {{ org_note_form.prefix }}">
{{ form.note.errors }}
{{ form.note.label_tag }}
{{ form.note }}
</div>
</fieldset>
</table>
</div>
<div>
<input style="margin-top: 30px;" type="submit" class="btn btn-primary" value="Save" />
</div>
</form>
</div>
</div> {% endblock %}
{% block javascripts %}
<script type="text/javascript">
$('#add_more').click(function() {
var form_idx = $('#id_form-TOTAL_FORMS').val();
$('#form_set').append($('#empty_form').html().replace(/__prefix__/g, form_idx));
$('#id_form-TOTAL_FORMS').val(parseInt(form_idx) + 1);
});
</script>
{% endblock %}
<script> $('#add_more').click(function() {
var form_idx = $('#id_organizationnote_set-TOTAL_FORMS').val();
$('#form_set').append($('#empty_form').html().replace(/__prefix__/g, form_idx));
$('#id_organizationnote_set-TOTAL_FORMS').val(parseInt(form_idx) + 1);
});</script>
the issue was solved by editing the prefix of the model manager. By default django names the prefix as table_set which was missing from above.
add another option to your code:
def form_invalid(self, form):
print(form.errors)
...
to see if you have any validation errors in your form, don't forget to check errors in your inline

How to create a search function on a class-based list view?

I am trying to create a search function based on the title of my posts. Right now I am trying to implement this search using a filter but the list view is not rendering. I am unsure if I should implement a URL for my search function.
This is my model:
class Post(models.Model):
title = models.CharField(max_length=100)
image = models.ImageField(default = 'default0.jpg', upload_to='course_image/')
description = models.TextField()
price = models.DecimalField(decimal_places=2, max_digits=6)
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
feedback = models.ManyToManyField(Feedback)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk' : self.pk})
This is my class-based list view:
class PostListView(ListView):
model = Post
template_name = 'store/sub_home.html' # <app>/<model>_<viewtype>.html
context_object_name = 'posts'
ordering = ['date_posted']
paginate_by = 12
def get_queryset(self):
object_list = super(PostListView, self).get_queryset()
search = self.request.GET.get('q', None)
if search:
object_list = object_list.filter(title__icontains = title)
return object_list
This is my search bar:
<div id="search">
<form method='GET' action=''>
<input type="text" name='q' placeholder="">
<button id='search_holder'>
<img src="/static/store/search_icon.gif" id="search_icon">
</button>
</form>
</div>
This is my html that is rendering the posts:
{% extends "store/base.html" %}
{% block content %}
{% include "store/home_ext.html" %}
<div style="padding-top: 20px;" id="main" >
<section class="text-center mb-4">
<div class="row" id="random">
{% for post in posts %}
{% include "store/card.html" %}
{% endfor %}
</div>
<div class="row" id="subscription" style="display: none;">
{% if not subs %}
<h2>You have not subscribed to any course :/</h2>
{% endif %}
{% for post in subs %}
{% include "store/card.html" %}
{% endfor %}
</div>
<div class="row" id="content" style="display: none;">
{% if not mine %}
<h2>You have not published anything :/</h2>
{% endif %}
{% for post in mine %}
{% include "store/card.html" %}
{% endfor %}
</div>
</section>
{% include "store/pagination.html" %}
</div>
{% endblock content %}
This is my card.html:
{% load extra_filter %}
<div class="col-lg-3 col-md-6 mb-4">
<div id="course_card">
<div class="view overlay">
<img style="margin-left: -10px;" src="{{ post.image.url }}" alt="">
</div>
<div>
<div>
<strong>
{% if user.is_authenticated %}
<a class="title" href="{% url 'post-detail' post.id %}" >
{% else %}
<a class="title" href="{% url 'login' %}" >
{% endif %}
{% if post.title|length < 30 %}
<span>{{ post.title }}</span>
{% else %}
<span>{{ post.title|cut:27 }}</span>
{% endif %}
<span style="background-color: rgb(253, 98, 98);" class="badge badge-pill danger-color">NEW
</span>
</a>
</strong>
</div>
<div class="star-ratings-css">
<div class="star-ratings-css-top" style="width: {{ post.feedback|calc_rating }}%"><span>★</span><span>★</span><span>★</span><span>★</span><span>★</span></div>
<div class="star-ratings-css-bottom"><span>★</span><span>★</span><span>★</span><span>★</span><span>★</span></div>
</div>
<a href="{% url 'user-posts' post.author.username %}" class="author">
by {{ post.author }}
</a>
<div>
<strong style="text-align: right;" class="price">S${{ post.price }}
</strong>
</div>
<small class="date">
{{ post.date_posted|date:'d F y'}}
</small>
</div>
</div>
</div>
As Nalin Dobhal mentioned in comments, context_object_name should be posts not post. Because in template, you are iterating through posts context variable. Also, when using search functionality, the implementation should be like this:
class PostListView(ListView):
model = Post
template_name = 'store/sub_home.html' # /_.html
context_object_name = 'posts'
ordering = ['date_posted']
paginate_by = 12
def get_queryset(self, *args, **kwargs):
object_list = super(PostListView, self).get_queryset(*args, **kwargs)
search = self.request.GET.get('q', None)
if search:
object_list = object_list.filter(title__icontains = search)
return object_list
Because you are sending the search query through URL querystring(ie: url will look like /posts/?q=title in browser). I am using request.GET.get('q') to fetch those query string values, and use it to filter the queryset.

modal form embedded in html does not work in django

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