part_stock_form.html
{{ update_form }}
part_detail.html
<div>
<form id="update_form" action="" method="post">
{% csrf_token %}
<div id="my_form">
{% if update_form %}
{{ update_form }}
{% else %}
{% include 'part_stock_form.html' %}
{% endif %}
</div>
<input type="submit" id="btn_stock_update" style="display: none;">
</form>
</div>
$(function () {
$('.edit_btn').on('click',pop_up);
function pop_up() {
var update_url = url to update stock;
$('#update_form').attr('action',update_url);
$("#my_form").load(update_url,function () {
$("#btn_stock_update").show();
});
});
</script>
UpdateView
class stock_update_view(UpdateView):
model = part_stock
fields = ['part_id','entry_date','supplier','amount','remaining']
success_url = reverse_lazy('parts:part_list')
template_name = 'part_stock_form.html'
def get_context_data(self, **kwargs):
context = super(stock_update_view, self).get_context_data(**kwargs)
context['update_form'] = context.get('form')
return context
def form_invalid(self, form):
print("form is invalid")
return render(self.request, 'part_details.html', {'update_form': form})
when the form is valid it works fine but when the form is invalid, an error is obtained
It seems that you have a typo in part_details.html when it should be part_detail.html
Related
My form is not saving to the database or at least i know the form is not valid i just dont know why? because it will always skip to the else in the if form.is_valid() (print("didnt work!"))
the view.py:
def index(request):
component = Component.objects.all()
form = ComponentModelForm()
if request.method == 'POST':
form = ComponentModelForm(request.POST)
if form.is_valid():
form.save()
return redirect('/maintenance')
else:
form = ComponentModelForm()
print("didnt work!")
context = {
'components': component,
'form': form,
}
return render(request, 'maintenance/index.html', context)
forms.py:
class ComponentModelForm(forms.ModelForm):
note = forms.CharField(widget=forms.Textarea)
image = forms.ImageField(error_messages = {'invalid':("Image files only")}, widget=forms.FileInput)
class Meta:
model = Component
fields = ("name",
"manufacturer",
"model",
"serial_number",
"price",
"note",
"image",
"parent",)
the template form:
{% load widget_tweaks %}
<form class="component-update-grid" enctype="multipart/form-data" method='POST' action=''>
{% csrf_token %}
<div class="component-form-data">
<span class="component-label-text">Name</span>
{% render_field form.name class="component-form-data-inputs" %}
<span class="component-label-text">Manufacturer</span>
{% render_field form.manufacturer class="component-form-data-inputs" %}
<span class="component-label-text">Model</span>
{% render_field form.model class="component-form-data-inputs" %}
<span class="component-label-text">Serial Number</span>
{% render_field form.serial_number class="component-form-data-inputs" %}
<span class="component-label-text">Price</span>
{% render_field form.price class="component-form-data-inputs" %}
<span class="component-label-text">Note</span>
{% render_field form.note class="component-form-data-inputs" %}
{% render_field form.parent class="component-form-data-inputs " %}
<input type="submit" class="button1" value='Create Component' />
</div>
<div class="component-form-img">
<img class="maintenance-component-img" src='{%static 'imgs/sidebar/logo.png'%} ' />
{% render_field form.image %}
</div>
</form>
You should not construct a new form when the form fails: a failed form will render the errors, such that the user knows what is going wrong, so:
def index(request):
component = Component.objects.all()
form = ComponentModelForm()
if request.method == 'POST':
form = ComponentModelForm(request.POST)
if form.is_valid():
form.save()
return redirect('/maintenance')
else:
# Don't create a new form!
print("didnt work!")
context = {
'components': component,
'form': form,
}
return render(request, 'maintenance/index.html', context)
I'm new to Python Django and I'm trying to set up a bound form with three fields where one field (which will be read only) takes an initial value and displays it on the form; the other two fields will be populated by the user when they completes the form. But when I try to submit the form, the form.is_valid returns false, and I'm not sure what I did wrong. Can anyone please help?
Thanks
Here's the code:
views.py
class AddKeyAccompView(TemplateView):
template_name = 'AddKeyAccomp.html'
def get(self, request, Program):
username = request.user.username
form = AddKeyAccompForm(request, Program=Program)
return render(request, self.template_name, {'form': form
,'title':'Add New Key Accomplishment'
,'User': username
})
def post(self, request, Program):
username = request.user.username
form = AddKeyAccompForm(request.POST, Program=Program)
if form.is_valid():
Name = form.cleaned_data['Name']
Description = form.cleaned_data['Description']
form.save()
form = AddKeyAccompForm(request, Program=Program)
return HttpResponseRedirect(reverse('ModInit', args=[Program]))
else:
return HttpResponse('invalid form')
args = {'form': form
,'title':'Add New Key Accomplishment'
,'User': username
,'Name': Name
,'Desc': Description
,'Program': Program
}
return render(request, self.template_name, args)
forms.py
class AddKeyAccompForm(forms.ModelForm):
def __init__(self, request, *args, **kwargs):
self.program = kwargs.pop('Program')
super(AddKeyAccompForm, self).__init__(*args, **kwargs)
self.fields['Program'].initial = self.program
class Meta:
model = Key_Accomplishments
fields = ('Name', 'Description', 'Program',)
widgets = {
'Name': forms.TextInput(attrs={'required':True, 'class':'form-control'})
,'Description': forms.Textarea(attrs={'required': True, 'class':'form-control'})
,'Program': forms.TextInput(attrs={'readonly':'readonly', 'class':'form-control'})
}
html file
{% extends 'base.html' %}
<!DOCTYPE html>
<html>
<head>
{% block head %}
<title>New Key Accomplishment</title>
{% endblock %}
</head>
<body>
{% block body %}
<div class="container">
<ol class="breadcrumb my-4">
<li class="breadcrumb-item active">
<center>{{ title }}</center>
</li>
</ol>
</div>
<br>
<div class="offset-3 col-md-6">
<form method="post">
{% csrf_token %}
<div class="form-group" style="padding-left:10%;">
{% for field in form %}
<label>{{ field.label_tag }}</label>
{{ field }}
<br>
{% endfor %}
</div>
<div class="btn" style="padding-left: 10%;">
<button type="submit">Submit</button>
</div>
</form>
</div>
{% endblock %}
</body>
</html>
I have a view where they are multiple posts and I want when the user like one of them, the form take the user_id and the post_id and save it into the DB. This is th Models.py:
class LikePost(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Posts, on_delete=models.CASCADE)
def __str__(self):
return '{} - {}'.format(self.user.username, self.post.name)
Forms.py:
class LikePostForm(forms.ModelForm):
class Meta:
model = LikedShops
fields = ['user', 'post']
widgets = {
'user': forms.HiddenInput(),
'post': forms.HiddenInput()
}
Views.py:
def posts(request):
if request.method == 'POST':
form = LikePostForm(request.POST)
if form.is_valid():
u = form.save(commit=False)
u.user = request.user
u.save()
return redirect('posts')
else:
form = LikePostForm()
context = {
'posts': Posts.objects.all(),
'form': form
}
return render(request, "posts.html", context)
and this the form in posts.html:
{% for post in posts %}
<div class="col-md-3">
<article class="card mb-4">
<header class="card-header">
<h4 class="card-title"><b>{{ post.name }}</b></h4>
</header>
<img style="width: 100%; height: 150px;" class="card-img" src="{{ post.image.url }}"/>
<div class="card-body">
<p class="card-text">{{ post.description }}</p>
</div>
{% if user.is_authenticated %}
<div class="card-footer">
<div class="row">
<div class="col">
<form action="/posts/" method="post">
{% csrf_token %}
{{ l_form|crispy }}
<button type="submit" class="btn btn-outline-success">Like</button>
</form>
</div>
</div>
</div>
{% endif %}
</article><!-- /.card -->
</div>
{% endfor %}
This is my edit, I did what you said, I made changes to:
forms.py:
class Meta:
model = Liked
fields = ['user', 'post']
widgets = {
'user': forms.HiddenInput(),
'post': forms.HiddenInput()
}
posts.html:
<form action="/posts/" method="post">
{% csrf_token %}
<input type="hidden" name="post" value="{{ post.pk }}">
{{ l_form|crispy }}
<button type="submit" class="btn btn-outline-success">Like</button>
</form>
views.py:
def posts(request):
if request.method == 'POST':
l_form = LikePostForm(request.POST, instance=request.user.profile)
if l_form.is_valid():
u = l_form.save(commit=False)
u.post = Posts.objects.filter(pk=l_form.cleaned_data.get('post')).first()
u.save()
messages.success(request, f"Form is valid!")
else:
messages.warning(request, f'Form is not valid! {request.POST}')
else:
l_form = LikePostForm(instance=request.user.profile)
context = {
'post': Posts.objects.all(),
'l_form': l_form
}
return render(request, "posts.html", context)
Now when I click the Like button, I got this message **Form is not valid! <QueryDict: {'csrfmiddlewaretoken': ['cNk9ZDS33Nj0l95TBfwtedL1jjAbzDSrH15VjMNZAcxjQuihWNZzOkVnIyRzsjwN'], 'post': ['1', ''], 'user': ['1']}>**
There are a couple of issues with your code.
First, the __str__() method should return a string and not a tuple
class LikePost(models.Model):
...
def __str__(self):
return '{} - {}'.format(self.user.username, self.post.name)
Second, there is a typo; change Pots to Posts:
context = {
'posts': Posts.objects.all(),
'form': form,
}
return render(request, "posts.html", context)
And third and last, the line u.post = request.post is throwing the error you mention, because the request object has no attribute post.
So change your form code to add the post in hidden state (I used fields instead of exclude):
class LikePostForm(forms.ModelForm):
class Meta:
model = LikePost
fields = ['post', ]
widgets = {
'post': forms.HiddenInput(),
}
and then change your view:
form = LikePostForm(request.POST)
if form.is_valid():
u = form.save(commit=False)
u.user = request.user
u.save()
After edit to the question:
Try adding post.pk as a hidden input in your form:
<form action="/posts/" method="post">
{% csrf_token %}
<input type="hidden" name="post" value="{{ post.pk }}">
{{ l_form|crispy }}
<button type="submit" class="btn btn-outline-success">Like</button>
</form>
or you can also do in your view:
u.post = Posts.objects.filter(pk=form.cleaned_data.get('post')).first()
I am building a view that will let me update multiple fields on multiple objects at the same time. I'm doing this using ModelFormSet & modelformset_factory.
The template will be a table of forms with the object name to the left of the fields (see image below).
I found this example, but I am stuck on how to implement the class based view & template.
My Formset
class BaseFormSet(BaseModelFormSet):
def __init__(self, *args, **kwargs):
super(BaseFormSet, self).__init__(*args, **kwargs)
self.queryset = Reference.objects.filter(
start__isnull=True)
ReferenceFormSet = modelformset_factory(
Reference,
fields=('start', 'end'),
formset=BaseFormSet,
extra=0)
My View
class ReferenceFormSetView(LoginRequiredMixin, SuperuserRequiredMixin, FormView):
model = Reference
form_class = ReferenceFormSet
template_name = "references/references_form.html"
def form_valid(self, form):
for sub_form in form:
if sub_form.has_changed():
sub_form.save()
return super(ReferenceFormSetView, self).form_valid(form)
My Template
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="container">
<h1>{{ headline }}</h1>
<div class="row">
<form action="" method="post">
{% crispy form %}
<div class="">
<input type="submit" value="Submit" />
</div>
</form>
</div>
</div>
{% endblock content %}
Questions
The view seems odd with the Formset in the form_class. Is there a better way to handle this?
How can I access the instance name to display in the form?
I found a solution using a package called django-extra-views.
There is a class called ModelFormSetView which does exactly what I wanted. Here is my implementation (simplified) for others to use -
My View
class ReferenceFormSetView(ModelFormSetView):
model = Reference
template_name = "references/references_form.html"
fields = ['start', 'end']
extra = 0
def get_queryset(self):
return self.model.objects.all()
def get_success_url(self):
return reverse('references:formset')
def formset_valid(self, formset):
"""
If the formset is valid redirect to the supplied URL
"""
messages.success(self.request, "Updated")
return HttpResponseRedirect(self.get_success_url())
def formset_invalid(self, formset):
"""
If the formset is invalid, re-render the context data with the
data-filled formset and errors.
"""
messages.error(self.request, "Error dummy")
return self.render_to_response(self.get_context_data(formset=formset))
My Template
<form class="" method="post">
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset %}
<div class="">
{% for field in form %}
{{ field }}
{% endfor %}
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">Save</button>
</form>
When I submit this form, neither are saved in the database but the HttpResponseRedirect works successfully. Any ideas why?
views.py
#login_required
def entry(request):
fantasyTeamForm = FantasySeasonForm() #Form to store each player in the fantasy team
seasonUserTournForm = PartialSeasonEntryForm()
season_tournament_id = 1
tournament_classic = Tournament(pk=season_tournament_id)
user_instance = request.user
if request.method == 'POST':
fantasyTeamForm = FantasySeasonForm(request.POST or None)
fantasyTeamForm.fields
if fantasyTeamForm.is_valid():
fantasyTeamForm.save(commit=False)
seasonUserTourn = ClassicSeasonUserList(
tournament=tournament_classic,
fantasy_team=fantasyTeamForm['FANTASY_TEAM_ID'],
user=user_instance.id,
)
seasonUserTournForm = PartialSeasonEntryForm(request.POST or None, instance=seasonUserTourn)
seasonUserTournForm.fields
if seasonUserTournForm.is_valid():
seasonUserTournForm.save()
fantasyTeamForm.save()
return HttpResponseRedirect('/season/entrysuccess') #page on success
args = {}
args.update(csrf(request))
args['form'] = fantasyTeamForm
args['form2'] = seasonUserTournForm
return render_to_response('entry.html', args, context_instance=RequestContext(request))
entry.html
<h2><b>Choose your team:</b></h2><br>
{% for field in form %}
{{field.error}}
{% endfor %}
{% for field in form2 %}
{{field.error}}
{% endfor %}
<form action="/season/entrysuccess" method="post"> {% csrf_token %}
{{form2}}
<br><br>
{{form.as_ul}}
<br>
<input type="submit" value="Submit Team" />
</form>
form action in html should have been:
<form action="/season/entry" method="post">
instead of
<form action="/season/entrysuccess" method="post">