POST request done successfully but data not saved in database - django

I'm trying to save form data in database by POST request, request successfully done but data not saved in database.
models.py
class Image(models.Model):
user = models.ForeignKey(User, related_name='images')
tagName = models.CharField(max_length=255)
instance = models.CharField(max_length=255)
forms.py
class BuildImageForm(forms.ModelForm):
class Meta:
fields = ('user', 'tagName', 'instance')
model = Image
views.py
class BuildImage(LoginRequiredMixin, CreateView):
form_class = BuildImageForm
model = Image
template_name = 'images/buildImage.html'
success_url = 'user/gui'
def get(self, request, *args, **kwargs):
objectlist = request.user.instances.all()
return render(request, 'images/buildImage.html', {'form': forms.BuildImageForm,
'objectlist': objectlist})
def form_valid(self, form):
instance = form.save()
instance.user = self.request.user
instance.tagName = self.request.tagName
instance.instance = str(self.request.instance_name)
instance.save()
return HttpResponse(status=200)
Update - Edited
I have update my view as:
def post(self, request, *args, **kwargs):
if request.method == 'POST':
form = BuildImageForm(request.POST)
if form.is_valid():
data = form.cleaned_data
form.instance.user = self.request.user
form.instance.tagName = data['tagName']
form.instance.instance = data['instance']
form.save()
else:
print(form.errors)
return HttpResponse(status=200)
Now it prints that error in console:
<ul class="errorlist"><li>instance<ul class="errorlist"><li>This field is required.</li></ul></li></ul>
[23/Jul/2017 04:36:56] "POST /user/images/buildImage/ HTTP/1.1" 200 0

Try changing your view method like this,
def form_valid(self, form):
instance = form.save(commit=False)
instance.user = self.request.user
instance.save()
return HttpResponse(status=200)

you are actually saving the file before adding data
def form_valid(self, form):
instance = form.save(commit=False)
instance.user = self.request.user
instance.tagName = self.request.tagName
instance.instance = str(self.request.instance_name)
instance.save()
return HttpResponse(status=200)

My issue has been solved just by providing a title attribute in my template for instance input field.
Updated code as:
buildImage.html
<form class="form-horizontal" method="POST" id="dockerForm">
{% csrf_token %}
<fieldset>
{% if not objectlist %}
<h3><strong>Sorry!</strong> You couldn't have created any Instance yet! <strong>Let's Create One </strong></h3>
{% else %}
<div class="form-group">
<span class="col-md-1 col-md-offset-2 text-center"><label for="package">Select Your Instance:</label></span>
<div class="col-md-8">
<select class="form-control" name="instance" id="instance_id" title="Select your Instance">
{% for element in objectlist %}
<option value={{ element.name }}> {{ element.name }} </option>
{% endfor %}
</select>
{% endif %}
</div>
</div>
</fieldset>
</form>
forms.py
class BuildImageForm(forms.ModelForm):
class Meta:
fields = ('tagName', 'instance')
model = Image
views.py
def post(self, request, *args, **kwargs):
if request.method == 'POST':
form = BuildImageForm(request.POST)
if form.is_valid():
data = form.cleaned_data
form.instance.user = self.request.user
form.instance.tagName = data['tagName']
form.instance.instance = data['instance']
form.save()
else:
print(form.errors)
return HttpResponseRedirect(reverse('users:gui'))

try to set try and cache for database operation
may be there is some error cached in cache section
Update
try:
"save to database code here"
except Exception as e:
print "error here" print e

Related

How do I properly implement Django formsets with a CreateView ( Class Based View )?

And thanks in advance for any suggestions. I have been playing around with how to properly implement formsets with a CreateView for a couple of days and I'm stuck. Here is my code.
My Models:
class Team(models.Model):
team_name = models.CharField(max_length=264,null=False,blank=False)
class Player(models.Model):
player_name = models.CharField(max_length=264,null=False,blank=False)
team = models.ForeignKey(Team,null=True,on_delete=models.CASCADE)
My View:
class CreateTeamView(LoginRequiredMixin,CreateView):
model = Team
form_class = CreateTeamForm
template_name = 'create_team.html'
def get_context_data(self, **kwargs):
context = super(CreateTeamView, self).get_context_data(**kwargs)
if self.request.POST:
context['new_player'] = NewPlayerFormSet(self.request.POST)
else:
context['nwe_player'] = NewPlayerFormSet()
return context
def get_form_kwargs(self, *args, **kwargs):
kwargs = super(CreateTeamView, self).get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
def form_valid(self, form):
context = self.get_context_data()
new_player_form = context['new_player']
if new_player_form.is_valid():
self.object = form.save()
new_player_form.instance = self.object
new_player_form.save()
instance = form.save()
else:
return self.render_to_response(self.get_context_data(form=form))
My Forms:
class CreateTeamForm(forms.ModelForm):
class Meta:
model = Team
exclude = []
NewPlayerFormSet = inlineformset_factory(Team, Player, extra=1, fields=['player_name',])
My HTML:
<div="players>
<div="add_players">
{{ new_player.management_form }}
{% for form in new_player %}
{{ form.id }}
{{ form.player_name }}
</div>
</div>
My form is saving one player, but when I try to update the code to save more than one player with the initial CreateView, it only recognizes the first contact. I have overridden the BaseInlineFormset to do validation as shown below....
class NewPlayerFormSet(NewPlayerFormSet,BaseInlineFormSet):
player_name = forms.CharField(required=True,widget=forms.TextInput)
def add_fields(self, form, index):
super(NewPlayerFormSet,self).add_fields(form,index)
form.fields['player_name'].required = False
def clean(self):
super(NewPlayerFormSet, self).clean()
for form in self.forms:
if form.cleaned_data.get('player_name'):
pass
else:
form.add_error('player_name','Player Name is required.')
pass
I'm trying to get the code to save a second contact. I have used tried various JQuery attempts....but am unclear if my problem is with JQuery or mayby my HTML templates? That's where I'm stuck.
I tried to do something like...
$(document).ready(function() {
// Watch for the 'add player' click
$('#add_player').click(function(e) {
e.preventDefault();
$('div.add_player:last').clone().each(function(i) {
$(this).find('input,select').each(function(i) {
// Remove any existing values
$(this).val('');
}).appendTo('div#players');
});
});
And while this works to duplicate the form, the players beyond number 1 are not being saved. Not sure what I'm doing incorrectly.
It would appear there is a JQuery plugin for this, but I'm trying to avoid using it for a number of reasons. Thanks again for any help to point me in the right direction.
This was not easy. I spent about a week trying to piece this all together. Here are all of the parts that I used to finally make it work. I ultimately did wind up using jquery.formset.js from GitHub in my solution. Hope I save someone a week.
class Team(models.Model):
team_name = models.CharField(max_length=264,null=False,blank=False)
class Player(models.Model):
player_name = models.CharField(max_length=264,null=False,blank=False)
team = models.ForeignKey(Team,null=True,on_delete=models.CASCADE)
My Views.py
class CreateTeamView(LoginRequiredMixin,CreateView):
model = Team
form_class = TeamForm
template_name = 'create_team.html'
def get(self, request, *args, **kwargs):
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
player_form = CreatePlayerFormSet()
return self.render_to_response(
self.get_context_data(form=form,
player_form=player_form,
))
def form_valid(self, form, player_form):
self.object = form.save()
player_form.instance = self.object
player_form.save()
instance = form.save()
def form_invalid(self, form, player_form):
return self.render_to_response(
self.get_context_data(form=form,
player_form=player_form,
))
def post(self, request, *args, **kwargs):
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
player_form = CreatePlayerFormSet(self.request.POST)
if (form.is_valid() and player_form.is_valid()):
return self.form_valid(form, player_form)
else:
return self.form_invalid(form, player_form)
My Forms.py
class CreateTeamForm(forms.ModelForm):
class Meta:
model = Team
exclude = [ ]
CreatePlayerFormSet = inlineformset_factory(Team, Player, extra=1, fields=(['player_name'])
My HTML Template: ( Using jquery/jquery.formset.js )
<script src="{% static 'jquery/jquery.formset.js' %}"></script>
<script type="text/javascript">
$(function() {
$(".inline.{{ player_form.prefix }}").formset({
prefix: "{{ player_form.prefix }}",
})
})
</script>
<form method="POST" enctype="multipart/form-data" id="forms">
{% csrf_token %}
{{ player_form.management_form }}
{{ player_form.non_form_errors }}
{% for form in player_form %}
{{ form.id }}
<div class="inline {{ player_form.prefix }}">
<div class="leftwidth22">
<div class="width52">
<h2 class="floatright23">Player Name - </h2>
</div>
</div>
<div class="rightwidth53">
<h2 class="width70">
{{ form.player_name }}
</h2>
</div>
{% endfor %}

Inlineformset_factory saving parent without child and not displaying validation errors if child is none

I am having 2 issues, one if you submit and click back and then submit again it duplicates the instance in the database - in this case Household. In addition it is saving the parent 'Household' without the child 'Applicants' despite me setting min_num=1
can someone point me in the right direction to resolve this issue.
Many thanks in advance
class Application(models.Model):
name = models.CharField(max_length=100, blank=True, null=True)
application_no = models.CharField(max_length=100, unique=True, default=create_application_no)
created_date = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE
)
class HouseHold(models.Model):
name = models.CharField(max_length=100)
application = models.ForeignKey(Application, on_delete=models.CASCADE)
no_of_dependents = models.PositiveIntegerField(default=0)
class Applicant(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
household = models.ForeignKey("HouseHold", on_delete=models.CASCADE)
forms.py
class ApplicationForm(ModelForm):
class Meta:
model = Application
fields = (
"name",
)
class ApplicantForm(ModelForm):
class Meta:
model = Applicant
fields = [
"household",
"first_name",
"last_name"
]
class HouseHoldForm(ModelForm):
class Meta:
model = HouseHold
fields = [
'name',
'application',
'no_of_dependents'
]
def __init__(self, application_id=None, *args, **kwargs):
super(HouseHoldForm, self).__init__(*args, **kwargs)
self.fields['name'].label = 'House Hold Name'
if application_id:
self.fields['application'].initial = application_id
self.fields['application'].widget = HiddenInput()
ApplicantFormset = inlineformset_factory(
HouseHold, Applicant, fields=('household', 'first_name', 'last_name'), can_delete=False, extra=1, validate_min=True, min_num=1)
views.py
class HouseHoldCreateView(LoginRequiredMixin, generic.CreateView):
model = models.HouseHold
template_name = "households/household_create.html"
form_class = HouseHoldForm
def get_parent_model(self):
application = self.kwargs.get('application_pk')
return application
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if self.request.POST:
context['application'] = models.HouseHold.objects.filter(application_id=self.kwargs['application_pk']).last()
context['house_hold_formset'] = ApplicantFormset(self.request.POST, instance=self.object)
else:
context['application'] = models.Application.objects.get(id=self.kwargs['application_pk'])
context['house_hold_formset'] = ApplicantFormset()
return context
def get_form_kwargs(self):
kwargs = super(HouseHoldCreateView, self).get_form_kwargs()
print(kwargs)
kwargs['application_id'] = self.kwargs.get('application_pk')
return kwargs
def form_valid(self, form):
context = self.get_context_data()
applicants = context['house_hold_formset']
with transaction.atomic():
self.object = form.save()
if applicants.is_valid():
applicants.instance = self.object
applicants.save()
return super(HouseHoldCreateView, self).form_valid(form)
def get_success_url(self):
if 'addMoreApplicants' in self.request.POST:
return reverse('service:household-create', kwargs={'application_pk': self.object.application.id})
return reverse('service:household-list', kwargs={'application_pk': self.object.application.id})
I had a similar problem, I solved it by adding the post() method to the view. The example is an UpdateView but the usage is the same.
(the indentation is not correct but that's what stackoverflow's editor let me do, imagine all methods are 4 spaces to the right)
class LearnerUpdateView(LearnerProfileMixin, UpdateView):
model = User
form_class = UserForm
formset_class = LearnerFormSet
template_name = "formset_edit_learner.html"
success_url = reverse_lazy('home')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
learner = User.objects.get(learner=self.request.user.learner)
formset = LearnerFormSet(instance=learner)
context["learner_formset"] = formset
return context
def get_object(self, queryset=None):
user = self.request.user
return user
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form_class = self.get_form_class()
form = self.get_form(form_class)
user = User.objects.get(learner=self.get_object().learner)
formsets = LearnerFormSet(self.request.POST, request.FILES, instance=user)
if form.is_valid():
for fs in formsets:
if fs.is_valid():
# Messages test start
messages.success(request, "Profile updated successfully!")
# Messages test end
fs.save()
else:
messages.error(request, "It didn't save!")
return self.form_valid(form)
return self.form_invalid(form)
Keep in mind that to save the formset correctly you have to do some heavy lifting in the template as well. I'm referring to the hidden fields which can mess up the validation process. Here's the template corresponding to the view posted above:
<form action="" method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
{{ learner_formset.management_form}}
{% for form in learner_formset %}
{% if forloop.first %}
{% comment %} This makes it so that it doesnt show the annoying DELETE checkbox {% endcomment %}
{% for field in form.visible_fields %}
{% if field.name != 'DELETE' %}
<label for="{{ field.name }}">{{ field.label|capfirst }}</label>
<div id="{{ field.name }}" class="form-group">
{{ field }}
{{ field.errors.as_ul }}
</div>
{% endif %}
{% endfor %}
{% endif %}
{% for field in form.visible_fields %}
{% if field.name == 'DELETE' %}
{{ field.as_hidden }}
{% else %}
{# Include the hidden fields in the form #}
{% if forloop.first %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endif %}
{% endif %}
{% endfor %}
{% endfor %}
<input class="btn btn-success" type="submit" value="Update"/>
Additional reading :
https://medium.com/#adandan01/django-inline-formsets-example-mybook-420cc4b6225d
Save formset in an UpdateView
Inspired by Beikini
I have solved it using the create View
class HouseHoldCreateView(LoginRequiredMixin, generic.CreateView):
model = HouseHold
template_name = "households/household_create3.html"
form_class = HouseHoldForm
def get_parent_model(self):
application = self.kwargs.get('application_pk')
return application
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if self.request.POST:
context['application'] = HouseHold.objects.filter(
application_id=self.kwargs['application_pk']).last()
context['house_hold_formset'] = ApplicantFormset(self.request.POST)
else:
context['application'] = Application.objects.get(id=self.kwargs['application_pk'])
context['house_hold_formset'] = ApplicantFormset()
return context
def get_form_kwargs(self):
kwargs = super(HouseHoldCreateView, self).get_form_kwargs()
kwargs['application_id'] = self.kwargs.get('application_pk')
return kwargs
def form_valid(self, form):
context = self.get_context_data()
applicants = context['house_hold_formset']
application_id = self.kwargs['application_pk']
household_form = self.get_form()
if form.is_valid() and applicants.is_valid():
with transaction.atomic():
self.object = form.save()
applicants.instance = self.object
applicants.save()
messages.success(self.request, 'Applicant saved successfully')
return super(HouseHoldCreateView, self).form_valid(form)
else:
messages.error(self.request, 'please add an applicant to the household')
return self.form_invalid(form)
def get_success_url(self):
return reverse('service:household-list', kwargs={'application_pk': self.object.application.id})

update formset with class based view

i've created web blog with django 2.2 each post has multiple images , but when i try to update the post
images wont updated
i use class based view
class Post(models.Model):
user= models.ForeignKey(Account,on_delete=models.CASCADE)
title= models.CharField(max_length=100)
#others
class PostImage(models.Model):
post= models.ForeignKey(Post,on_delete=models.CASCADE,related_name='images')
media_files = models.FileField(upload_to=random_url)
and this my forms.py
class PostImageForm(forms.ModelForm):
class Meta:
model = PostImage
fields = [
'media_files'
]
class PostUpdateForm(forms.ModelForm):
class Meta:
model = Post
fields = [
'title','description',#and others
]
my views.py
PostImageFormSet = inlineformset_factory(
Post,PostImage,form=PostImageForm,extra=1,can_delete=True,can_order=False
)
class PostUpdateView(LoginRequiredMixin,UserPassesTestMixin,UpdateView):
model = Post
form_class = PostUpdateForm
template_name = 'posts/update_post.html'
def get_context_data(self,**kwargs):
data = super().get_context_data(**kwargs)
if self.request.POST:
data['images'] = PostImageFormSet(self.request.POST or None,self.request.FILES,instance=self.object)
else:
data['images'] = PostImageFormSet(instance=self.object)
return data
def form_valid(self,form):
context = self.get_context_data()
images = context['images']
with transaction.atomic():
if form.is_valid() and images.is_valid():
self.object = form.save()
images.instance = self.object
images.save()
return super().form_valid(form)
def test_func(self):
post = self.get_object()
if self.request.user.username == post.user.username:
return True
return False
def get_success_url(self):
return reverse_lazy('post:post-detail',kwargs={'slug':self.object.slug})
my templates
<form enctype="multipart/form-data" method="post" action="">
{% csrf_token %}
{{images.management_form }}
{{ form|crispy }}
{% for img in images %}
<label>{{img.media_files.label}}</label>
{{img.media_files}}
{% endfor %}
<button type="submit" class="btn btn-block btn-primary">update</button>
</form>
i'm wondering why didnt update the posts image !?
thanks for replay ..

Django web app not redirecting and not posting

I an not sure where is the problem as I press submit button, it went through with no error shown. It was supposed to update the database with the data filled in form then redirect them back to 'search' page (option.html).
models.py:
OptionChoice = (
('A','A'),
('B','B'),
('C','C'),
)
class OptionPlan(models.Model):
option = models.CharField(max_length=200, choices=OptionChoice, default="DEFAULT", blank=True)
...
updated = models.DateField(max_length=20, null=True)
updatedBy = models.CharField(max_length=10, null=True)
urls.py:
app_name = 'Benefits'
urlpatterns = [
path('simple_upload', views.simple_upload, name='simple_upload'),
#path('search', views.search, name='search'),
path('search/', FilterView.as_view(filterset_class=BenefitsFilter, template_name='Benefits/option.html'), name='search'),
path('OptionUpdate/<int:id>', views.OptionUpdate.as_view(), name='OptionUpdate')
]
views.py:
def search(request):
option = OptionPlan.objects.get_queryset()
option_filter = BenefitsFilter(request.GET, queryset=option)
return render(request, 'Benefits/option.html', {'filter':option_filter})
class OptionUpdate(UpdateView):
model = OptionPlan
fields =[
'option',
...
'cb_updatedBy',
'cb_updated',
]
template_name = 'Benefits/OptionUpdate.html'
slug_field = 'id'
slug_url_kwarg = 'id'
def form_valid(self, request, obj, form, change):
OptionPlan = form.save(commit=False)
if OptionPlan.option and 'option' in form.changed_data:
OptionPlan.updatedBy = str(self.request.user)
OptionPlan.updated = timezone.localtime(timezone.now())
OptionPlan.save()
return redirect('Benefits:search')
optionUpdate.html:
{% if user.is_authenticated %}
<div style="margin-left:100px;margin-right:100px;">
<form method="POST">
<div class="row">
<div class="col">
<h2 class="alert alert-primary">...</h2>
{% csrf_token %}
<div class="row">
<div class="col-4" style="font-size:30px;">
{{ form.option|as_crispy_field }}
</div>
</div>
...
<div class="col">
<h2 class="alert alert-success">...</h2>
...
<div class="col" style="font-size:30px;">
{{ form.cb_remarks|as_crispy_field }}
</div>
</div>
<button type="submit" class="btn btn-primary btn-block">2020 Option Form Update</button>
</div>
</form>
</div>
{% else %}
Thank you so much for helping!
Edit:
What version of Django are you using? A cursory look at generic UpdateView* from Django v1.3 through v2.2 use this same post method:
def post(self, request, *args, **kwargs):
"""
Handle POST requests: instantiate a form instance with the passed
POST variables and then check if it's valid.
"""
form = self.get_form()
if form.is_valid(): <--- you passed here so your form is valid
return self.form_valid(form) <-- you overwrote this method (problem area)
else:
return self.form_invalid(form)
*get familiar with that website if you are using class based views, its a life saver.
I am not sure how your form_valid method is being called with four variables: request, obj, form, change when it only expects one variable.
I typically split this logic apart and would make a separate form:
forms.py
class OptionPlanUpdateForm(forms.ModelForm):
class Meta:
model = OptionPlan
fields = [
'option',
'cb_updatedBy',
...
'cb_updated',
]
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user', None)
super().__init__(*args, **kwargs)
def save(self, **kwargs):
option_plan = super().save(commit=False)
if 'option' in self.changed_data:
option_plan.updatedBy = str(self.user)
option_plan.updated = timezone.localtime(timezone.now())
option_plan.save()
return option_plan
Since we have a form we have to update our view to handle the form. We pass the user to the form through the get_form_kwargs method.
class OptionUpdate(UpdateView):
form_class = OptionPlanUpdateForm
model = OptionPlan
slug_field = 'id'
slug_url_kwarg = 'id'
template_name = 'Benefits/OptionUpdate.html'
success_url = reverse_lazy('Benefits:search')
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
***To test for errors in your form you can do the following:
def post(self, request, *args, **kwargs):
form = self.form_class(self.request.POST)
print(form.errors)
return super().post(request, *args, **kwargs)
If I were to assume, the form is throwing some type of error that you aren't printing nor handling. Try checking if any form errors exists to begin with.

How to pass a form view to another view as a context in django?

I'm using Django 1.8 to create an application. I have a Link model and a Comment model which has Link as a ForeignKey. I'm using generic views to generate a LinkDetailView and CommentCreateView and show them in separate template files and then include comment in link detail template. Here is the code:
views.py
class LinkDetailView(DetailView):
models = Link
queryset = Link.objects.all()
def get_context_data(self, **kwargs):
context = super(LinkDetailView, self).get_context_data(**kwargs)
context['form'] = CommentForm
return context
class CommentCreateView(CreateView):
form_class = CommentForm
template_name = "comments/comment_form.html"
def form_valid(self, form):
link = get_object_or_404(Link, pk=form.data["link"] )
f = form.save(commit=False)
f.user = self.request.user
f.link = link
f.save()
return super(CommentCreateView, self).form_valid(form)
link_detail.html
{% block content %}
. . .
{% include "comments/comment_form.html" %}
{% endblock %}
comment_form.html
<h2>Add Comment</h2>
<form action="" method="POST">
{% csrf_token %}
<table>
{{ form.as_p }}
</table>
<input type="submit" name="submit" value="Submit" />
</form>
The form shows up in the link detail page but when I click submit button it goes to nowhere [I see error "POST /links/1/slug/ HTTP/1.1" 405 0 in shell] and obviously doesn't save in database.
I'm not sure if I've chosen correct approach to do this, so any help would be appreciated.
I've solved the problem using FormMixin here's the docs
and here's how the views.py looks like now:
class LinkDetailView(FormMixin, DetailView):
models = Link
queryset = Link.objects.all()
form_class = CommentForm
def get_success_url(self):
return reverse('link_detail', kwargs={'pk': self.object.pk, 'slug': self.object.slug})
def get_context_data(self, **kwargs):
context = super(LinkDetailView, self).get_context_data(**kwargs)
context['form'] = self.get_form()
return context
def post(self, request, *args, **kwargs):
if not request.user.is_authenticated():
return HttpResponseForbidden()
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
link = get_object_or_404(Link, pk=self.object.pk)
print link
f = form.save(commit=False)
f.user = self.request.user
f.link = link
f.save()
return super(LinkDetailView, self).form_valid(form)