Trying to edit a form using django and python - python

I'm trying to edit the form via my edit button.
When i click update button in my form I'm getting the following error:
FieldError at /studentapp/editrow/72/
Cannot resolve keyword 'rowid' into field Choices are: address, course, id, name, pub_date, roll
My traceback shows the error originating in this line
item = get_object_or_404(Studentapp, rowid=id) this line.
My models.py looks like this:
class Studentapp(models.Model):
name = models.CharField(max_length=100)
roll = models.IntegerField()
course = models.CharField(max_length=100)
address = models.CharField(max_length=100)
pub_date = models.DateTimeField('date published', auto_now=True)
def __str__(self):
return '%s %s %s %s' % (self.name, self.roll, self.course, self.address)
def published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
EDIT
My view:
def editrow(request, id):
item = get_object_or_404(Studentapp, id=id)
if request.method=="POST":
form = EntryForm(request.POST, instance=item)
if form.is_valid():
post=form.save(commit=False)
post.save()
return HttpResponseRedirect(reverse('studentapp:index'), id)
else:
form=EntryForm(instance=item)
return render(request, 'index.html',{'form':form})
else:
form=EntryForm(instance=item)
return render(request, 'index.html',{'form':form})
My urls.py
url(r'^editrow/(?P<rowid>[0-9]+)/$', views.editrow, name='editrow'),
Form that i'm using to update the entry:
{% load staticfiles %}
<form action="{% url 'studentapp:editrow' student_detail.id %}" id="editform" method="POST">
{% csrf_token%}
<div class = "form-group">
<label for = "your_name">
Your name:
</label>
<input class = "form-control" id="new_name" type = "text" name="name" value="{{ student_detail.name }}" placeholder="Enter your name">
</div>
<div class="form-group">
<label for = "course_name">
Course:
</label>
<input id="new_course" class = 'form-control' type = "text" name="course" value="{{ student_detail.course }}" placeholder="Enter your course">
</div>
<div class = "form-group">
<label for = "rollno">
Roll No.:
</label>
<input id="new_rollno" type = "text" class = 'form-control' name="roll" value="{{ student_detail.roll }}" placeholder="Enter your roll number">
</div>
<div class = "form-group">
<label for ="addr">
Address:
</label>
<input id="new_address" type = "text" name="address" class = 'form-control' value="{{ student_detail.address }}" placeholder="Enter your address"/>
</div>
<input type = "submit" value="Update" id="update" class = "btn btn-success" style="font-size:18px;" />
</form>

This line is not right, your model does not have the field rowid
item = get_object_or_404(Studentapp, rowid=id) this line. # WRONG
item = get_object_or_404(Studentapp, id=id) this line. # OK
and your urls should be
url(r'^editrow/(?P<id>[0-9]+)/$', views.editrow, name='editrow'),
# url(r'^editrow/(?P<rowid>[0-9]+)/$', views.editrow, name='editrow'), # WRONG

Related

How can I handle the data of post requests in Django

I want to receive a request by adding several inputs to the form by the user.
I want to know how to control the received data separately.
in html file, {% for i in request.POST.items %} it works. but in views.py, it doesn't work like this
views.py
def debate_create(request):
if request.method == "POST":
content = request.POST
for k,v in content.items:
if k == 'sup_title':
sup_title = SuperTitle()
sup_title.author = request.user
sup_title.super_title = v
sup_title.save()
elif 'img' not in k and 'section' in k:
sub_title = Subtitle()
sub_title.super_title = sup_title.super_title.id
sub_title.sub_title = v
sub_title.save()
elif 'img' in k:
stg = Images()
imgs = request.FILES
stg.images = imgs
stg.sub_title = sub_title.sub_title.id
stg.save()
elif 'section' in k and 'opt' in k:
opt = SelectOption()
opt.sub_title = sub_title.sub_title.id
opt.option = v
return render(request, 'polls/test.html')
models.py
class SuperTitle(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='debate_author')
super_title = models.CharField(max_length=100)
liker = models.ManyToManyField(User, related_name='debate_liker')
class Subtitle(models.Model):
super_title = models.ForeignKey(SuperTitle, on_delete=models.CASCADE)
sub_title = models.TextField(blank=True)
class Images(models.Model):
sub_title = models.ForeignKey(Subtitle, on_delete=models.CASCADE)
images = models.ImageField(null=True)
class SelectOption(models.Model):
sub_title = models.ForeignKey(Subtitle, on_delete=models.CASCADE)
option = models.CharField(max_length=20)
option_voter = models.ManyToManyField(User)
html
<form method="POST" id="debate_form" action="{% url 'polls:debate_create' %}">
{% csrf_token %}
<input type='text' name='sup_title' placeholder='제목'>
<div id="form_container">
<section id='section_1'>
<input type="text" name="section_1">
<input type="file" name="img_section_1" multiple>
<div id="section_1_div">
<input type="text" name="section_1_opt_1" value="1">
<input type="text" name="section_1_opt_2" value="2">
</div>
<input type="button" value="add option" onclick='add_option(this.id)' id="section_1">
<input type="button" value="sub option" onclick='sub_option(this.id)' id="section_1">
</section>
</div>
<input type="button" value='add content' onclick='add_content()'>
<input type="button" value='sub content' onclick='sub_content()'>
<input type="submit">
</form>
There was a confusion between the django syntax in HTML and the syntax in python.
html
{% for i in request.POST.items %}
views.py
#for i in request.POST.items >>> syntaxerror
for i in request.POST.items():

How to do a logical operation before saving to database in python Django

So i am new to Django, and i want to make some hardware compatibility check feature in my app, i make a form to be filled and check the compatibility from database then show me the result. but the problem is the form seems to just keep saving to database without processing the logical operation first.
this is my view
class CreateSimView(LoginRequiredMixin, CreateView):
login_url = '/login/'
model = Simulation
form_class = SimPostForm
template_name = 'sim_post.html'
redirect_field_name = 'sim/sim.html'
def simpost(request):
mtb = Motherboard.objects.all()
cpu = Cpu.objects.all()
vga = Vga.objects.all()
ram = Ram.objects.all()
storage = Storage.objects.all()
mtbform = request.GET.get('mtb_name')
cpuform = request.GET.get('cpu_name')
vgaform = request.GET.get('vga_name')
ramform = request.GET.get('ram_name')
strform = request.GET.get('str_name')
simcpu = cpu.objects.values_list('socket', flat=True).filter(name__icontains=cpuform)
simcpu1 = mtb.objects.values_list('socket', flat=True).filter(name__icontains=mtbform)
simvga = vga.objects.values_list('vga_interface', flat=True).filter(name__icontains=vgaform)
simvga1 = mtb.objects.values_list('vga_interface', flat=True).filter(name__icontains=mtbform)
simram = ram.objects.values_list('mem_type', flat=True).filter(name__icontains=ramform)
simram1 = mtb.objects.values_list('mem_type', flat=True).filter(name__icontains=mtbform)
simstr = str.objects.values_list('str_interface', flat=True).filter(name__icontains=strform)
simstr1 = mtb.objects.values_list('str_interface', flat=True).filter(name__icontains=mtbform)
if simcpu == simcpu1 :
if simvga == simvga1:
if simram == simram1:
if simstr == simstr1:
form = SimPostForm(request.POST)
if form.is_valid():
form.save()
return render(mtbform,cpuform,vgaform,ramform,strform,"/")
else:
strform = "not compatible"
return render(mtbform,cpuform,vgaform,ramform,strform,"/")
else:
ramform = "not compatible"
return render(mtbform,cpuform,vgaform,ramform,strform,"/")
else:
vgaform = "not compatible"
return render(mtbform,cpuform,vgaform,ramform,strform,"/")
else:
cpuform = "not compatible"
return render(mtbform,cpuform,vgaform,ramform,strform,"/")
my models for the form
class Simulation(models.Model):
build_name = models.CharField(blank=False, max_length=150)
mtb_name = models.CharField(blank=False, max_length=150)
cpu_name = models.CharField(blank=False, max_length=150)
vga_name = models.CharField(blank=False, max_length=150)
ram_name = models.CharField(blank=False, max_length=150)
str_name = models.CharField(blank=False, max_length=150)
def __str__(self):
return self.build_name
def get_absolute_url(self):
return reverse('sim:sim_post')
and my template
{% extends "base.html" %}
{% load bootstrap4 %}
{% block content %}
<div class="container">
<div class="jumbotron">
<h1>Pilih Parts</h1>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="form-group">
<label for="build">Nama Rakitan</label>
<input class="form-control" type="text" id="build" name="build_name" value="{{ form.build_name.value|default_if_none:"" }}">
</div>
<div class="form-group">
<label for="mtb">Motherboard</label>
<input class="form-control" id="mtb" type="text" name="mtb_name" value="{{ form.mtb_name.value|default_if_none:"" }}">
</div>
<div class="form-group">
<label for="vga">Vga</label>
<input class="form-control" id="vga" type="text" name="vga_name" value="{{ form.vga_name.value|default_if_none:"" }}">
</div>
<div class="form-group">
<label for="ram">Ram</label>
<input class="form-control" type="text" id="ram" name="ram_name" value="{{ form.ram_name.value|default_if_none:"" }}">
</div>
<div class="form-group">
<label for="storage">Storage</label>
<input class="form-control" type="text" id="storage" name="str_name" value="{{ form.storage_name.value|default_if_none:"" }}">
</div>
<div class="form-group">
<label for="cpu">Cpu</label>
<input class="form-control" type="text" id="cpu" name="cpu_name" value="{{ form.cpu_name.value|default_if_none:"" }}">
</div>
<button type="submit" class="btn btn-secondary">Cek Kompatibilitas</button>
</form>
</div>
</div>
{% endblock %}
i also use {{ form.storage_name.value|default_if_none:"" }} in my form hoping it would return the value from before. but it doesn't seem to do that.
It seems to me that you implemented your logic in
def simpost(request)
but you missed to integrate the call of this function in the predefined processing of the CreateView.
So one approach might be to override
def post(self, request, *args, **kwargs)
of the CreateView and put your logic there. If everything is fine, you should call
super().form_valid(your_form_object_here)
to trigger the creation of your data with the predefined actions of the CreateView.

Issue in form validation

I want to validate my update form using form validation. When i leave a field blank and hit update button I get a blank page showing the error message. I want that error message to be displayed on top of that particular field when I leave it blank and hit update button.
This is my latest update view:
def update(request, id):
item = get_object_or_404(BookEntry, id=id)
if request.method == "POST":
form = UpdateForm(request.POST, instance=item)
# print template
error_messages = {
'error': form.errors,
}
if form.is_valid():
print(form.cleaned_data)
post = form.save(commit=False)
post.save()
return HttpResponseRedirect(reverse('bms:index'), id)
else:
form = UpdateForm()
return HttpResponse(json.dumps(error_messages))
return render(request, 'index.html',{'form':form})
This is my old update view:
def update(request, id):
item = get_object_or_404(BookEntry, id=id)
if request.method=="POST":
form = UpdateForm(request.POST, instance=item)
if form.is_valid():
post=form.save(commit=False)
post.save()
return HttpResponseRedirect(reverse('bms:index'), id)
else:
form=UpdateForm(instance=item)
return HttpResponseRedirect(reverse('bms:index'), id)
return render(request, 'bms.html',{'form':form})
This is my forms.py:
class UpdateForm(forms.ModelForm):
title = forms.CharField(max_length=100)
author = forms.CharField(max_length=100)
edition = forms.CharField(max_length=100)
publisher = forms.CharField(max_length=100)
genre = forms.CharField(max_length=100)
detail = forms.CharField(max_length=100)
language = forms.CharField(max_length=100)
price = forms.IntegerField()
dop = forms.CharField(max_length=100)
cop = forms.CharField(max_length=100)
copyright = forms.CharField(max_length=100)
isbn = forms.IntegerField()
class Meta:
model = BookEntry
fields = '__all__'
This is my html form:
<form action="{% url 'bms:update' book.id %}" id="updateform" name="updateform" method="POST">
{% csrf_token%}
<div class = "form-group">
<label for = "title">
Title:
</label>
<input class = "form-control" id="book_title" type = "text" name="title" value="{{ book.title }}">
</div>
<div class="form-group">
<label for = "author">
Author:
</label>
<input id="book_author" class = 'form-control' type = "text" name="author" value="{{ book.author }}">
</div>
<div class = "form-group">
<label for = "edition">
Edition:
</label>
<input id="book_edition" type = "text" class = 'form-control' name="edition" value="{{ book.edition }}">
</div>
<div class = "form-group">
<label for ="publisher">
Publisher:
</label>
<input id="book_publisher" type = "text" name="publisher" class = 'form-control' value="{{ book.publisher }}"/>
</div>
<div class = "form-group">
<label for ="genre">
Genre:
</label>
<input id="book_genre" type = "text" name="genre" class = 'form-control' value="{{ book.genre }}"/>
</div>
<div class = "form-group">
<label for ="detail">
Detail:
</label>
<input id="book_detail" type = "text" name="detail" class = 'form-control' value="{{ book.detail }}"/>
</div>
<div class = "form-group">
<label for ="language">
Language:
</label>
<input id="book_language" type = "text" name="language" class = 'form-control' value="{{ book.language }}"/>
</div>
<div class = "form-group">
<label for ="price">
Price:
</label>
<input id="book_price" type = "text" name="price" class = 'form-control' value="{{ book.price }}"/>
</div>
<div class = "form-group">
<label for ="dop">
DOP:
</label>
<input id="book_dop" type = "text" name="dop" class = 'form-control' value="{{ book.dop }}"/>
</div>
<div class = "form-group">
<label for ="cop">
COP:
</label>
<input id="book_cop" type = "text" name="cop" class = 'form-control' value="{{ book.cop }}"/>
</div>
<div class = "form-group">
<label for ="cop">
Copyright
</label>
<input id="book_copyright" type = "text" name="copyright" class = 'form-control' value="{{ book.copyright }}"/>
</div>
<div class = "form-group">
<label for ="isbn">
ISBN:
</label>
<input id="book_isbn" type = "text" name="isbn" class = 'form-control' value="{{ book.isbn }}"/>
</div>
<input type = "submit" value="Update" id="update" class = "btn btn-success" style="font-size:18px;" />
</form>
This is the URL it shows when a field is left empty:
http://127.0.0.1:8000/bms/update/2/
And this is the error message:
{"error": {"edition": ["This field is required."]}}
I had left edition field empty to check if validation is working properly or not.
Can anyone suggest me how to do it the right way?
As Daniel pointed out, you need to re-render the form.
The basics of HTTP Form Post are:
If the form is valid: save + do a HttpResponseRedirect
If the form is not valid; re-render the same template with the errors
Change your function to:
def update(request, id):
item = get_object_or_404(BookEntry, id=id)
if request.method == "POST":
form = UpdateForm(request.POST, instance=item)
# print template
error_messages = {
'error': form.errors,
}
if form.is_valid():
print(form.cleaned_data)
post = form.save(commit=False)
post.save()
return HttpResponseRedirect(reverse('bms:index'), id)
return render(request, 'index.html',{'form':form}) # Form invalid case is handled here; the form is reused from above; form.errors is available in the template now
else:
pass # Handle GET requests here

Trying to pass url in form action

I'm new in django and i'm stuck now.
I'm trying to pass the url in form [action] attribute that would go to my edit function defined in [views.py] file and do it's job but whenever I try to pass the url [NoReverseMatch] is shown.
This is what i tried to do:
<div class="modal fade" id="editform" role="dialog">
<div class="modal-dialog">
<div class = "modal-content">
<div class = "modal-header">
<button type = "button" class = "close" data-dismiss="modal">×</button>
<h3 class="modal-title">
<b>Edit Information</b>
</h3>
</div>
<div class = "modal-body">
<form action="{% url 'studentapp:editrow' rowid=id %}" id="editform" method="POST">
{% csrf_token %}
<div class = "form-group">
<label for = "your_name">
Your name:
</label>
<input class = "form-control" id="new_name" type = "text" name="name" value="{{ student_detail.name }}" placeholder="Enter your name">
</div>
<div class="form-group">
<label for = "course_name">
Course:
</label>
<input id="new_course" class = 'form-control' type = "text" name="course" value="{{ student_detail.course }}" placeholder="Enter your course">
</div>
<div class = "form-group">
<label for = "rollno">
Roll No.:
</label>
<input id="new_rollno" type = "text" class = 'form-control' name="roll" value="{{ student_detail.roll }}" placeholder="Enter your roll number">
</div>
<div class = "form-group">
<label for ="addr">
Address:
</label>
<input id="new_address" type = "text" name="address" class = 'form-control' value="{{ student_detail.address }}" placeholder="Enter your address"/>
</div>
<input type = "submit" value="Update" id="update" class = "btn btn-success" style="font-size:18px;" />
</form>
</div>
</div>
</div>
</div>
In my urls.py I've used the following url:
url(r'^editrow/(?P<rowid>[0-9]+)/$', views.editrow, name='editrow'),
My [editrow] view looks something like this:
def editrow(request, rowid):
item = get_object_or_404(Studentapp, rowid=id)
print item
if request.method=="POST":
form = EntryForm(request.POST, instance=item)
if form.is_valid():
post=form.save(commit=False)
post.save()
return HttpResponseRedirect(reverse('studentapp:index'),rowid.id)
else:
form=EntryForm(instance=item)
return render(request, 'index.html',{'form':form})
else:
form=EntryForm(instance=item)
return render(request, 'index.html',{'form':form})
View that render's the template:
def index(request):
context = {}
latest_student = Studentapp.objects.order_by('pub_date')
context.update({
'latest_student': latest_student
})
response = {"status": False, "errors": []}
if request.is_ajax():
id = request.POST['id']
response = {}
response['status'] = False
student_detail = Studentapp.objects.filter(id=id).first()
context = {
"student_detail": student_detail
}
template = render_to_string("studentapp/_edit_student.html", context)
response['template'] = template
response['status'] = True
return HttpResponse(json.dumps(response), content_type="applicaton/json")
return render(request, "studentapp/index.html", context)
What i'm doing in crud is:
1) make an [edit] button in table through for loop.
2) when i click [edit] button a pre-populated form shows up(which i'm getting).
3) After i click the pre-populated form i want to edit that form and save it and updated data is reflected in my django db.
Thanks to #Alasdair, I looked in my code what he was trying to tell me and i got the answer.
The url that i was trying to pass through my action attribute was wrong. Here's what i did.
<form action="{% url 'studentapp:editrow' rowid=student_detail.id %}" id="editform" method="POST">
Through "student_detail" i'm able to get pre-populated form as i mentioned above. i used the same to get the id and pass it to my "editrow" view.
It's working for me now.
It seems like you never add id to your context in your view index. So the template does not have that variable available.
You need to add that id to your context.
Just like #Alasdair pointed out in the comments.

I have a bound ModelForm that is invalid

I am trying to create a ModelForm that links to an external database, and when you submit the form the external database gets updated. The problem comes when I check the validity of the form, it is invalid.
I have done some researching into this and found the most common problem was that the form is not bound, but when I use print(form.non_field_errors) I get:
<bound method BaseForm.non_field_errors of <EmailForm bound=True, valid=False, fields=(subject;body;name;altsubject;utm_source;utm_content;utm_campaign)>
models.py:
class MarketingEmails(models.Model):
messageid = models.AutoField(db_column='column1', primary_key=True)
subject = models.CharField(db_column='column2', max_length=2000)
body = models.TextField(db_column='column3') #using a text field as there is no maximum length
name = models.CharField(db_column='column4', max_length=25)
altsubject = models.CharField(db_column='column5', max_length=2000)
utm_source = models.CharField(db_column='column6', max_length=25)
utm_content = models.CharField(db_column='column7', max_length=25)
utm_campaign = models.CharField(db_column='column8', max_length=25)
class Meta:
managed = False
db_table = ''
forms.py:
class EmailForm(forms.ModelForm):
class Meta:
model = MarketingEmails
fields = ['messageid','subject','body','name','altsubject','utm_source','utm_content','utm_campaign']
views.py:
def emailinfo(request, pk):
if request.session.has_key('shortname'):
shortname = request.session['shortname']
rows = get_object_or_404(MarketingEmails, pk=pk)
if request.method == 'POST':
form = EmailForm(request.POST)
print(form.errors)
print(form.non_field_errors)
if form.is_valid():
form.save()
print("form is valid")
return redirect('marketingemails:emailinfo', pk = rows.messageid)
return render(request, 'marketingemails/emailinfo.html',{'shortname': shortname, 'rows': rows})
else:
return HttpResponseRedirect(reverse('common:login'))
urls.py:
app_name = 'marketingemails'
urlpatterns = [
url(r'^marketing/emails/(?P<pk>[0-9]+)/$', marketingviews.emailinfo, name='emailinfo'),
]
html:
<form method="POST" class="post-form" action ="">
{% csrf_token %}
<label for="exampleTextarea">Name</label>
<textarea class="form-control" id="exampleTextarea" rows="1">{{ rows.name }}</textarea>
<label for="exampleTextarea">Subject</label>
<textarea class="form-control" id="exampleTextarea" rows="1">{{ rows.subject }}</textarea>
<label for="exampleTextarea">Alternative Subject</label>
<textarea class="form-control" id="exampleTextarea" rows="1">{{ rows.altsubject }}</textarea>
<label for="exampleTextarea">Body</label>
<div class="ibox-content no-padding">
<div class="summernote">
{{ rows.body }}
</div>
</div>
<label for="exampleTextarea">utm_source</label>
<textarea class="form-control" id="exampleTextarea" rows="1">{{ rows.utm_source }}</textarea>
<label for="exampleTextarea">utm_content</label>
<textarea class="form-control" id="exampleTextarea" rows="1">{{ rows.utm_content }}</textarea>
<label for="exampleTextarea">utm_campaign</label>
<textarea class="form-control" id="exampleTextarea" rows="1">{{ rows.utm_campaign }}</textarea>
<button type="submit" class="save btn btn-default">Save</button>
</form>
Your HTML form doesn't name the fields so the form can't get them. You want to use the form for rendering too : https://docs.djangoproject.com/en/1.11/topics/forms/#working-with-form-templates

Categories