Field 'id' expected a number but got 'POST' - django

This is my view:
def edit_bendrija_view(request, bendrija_id):
""" A view to edit Bendrijos name """
bendrija = get_object_or_404(Bendrija, id=bendrija_id)
if request.method == 'POST':
existing_bendrija = BendrijaForm(request.POST, instance=bendrija)
if existing_bendrija.is_valid():
existing_bendrija.save()
messages.success(request, "Your Bendrija Was Updated")
return redirect(reverse('bendrijos'))
else:
messages.error(request, "Your Bendrija Was Not Updated")
existing_bendrija = BendrijaForm(instance=bendrija)
context = {
'existing_bendrija': existing_bendrija,
"bendrija": bendrija,
}
return render(request, 'home/edit_bendrija.html', context)
I am trying to edit an existing model using a form, the model only has 2 CharFields so its very simple, everything works up until I click the submit button, then the error that is the title comes up, and I am completely lost, especially because the error says the problem is on the "bendrija = get_object_or_404(Bendrija, id=bendrija_id)" line,
this is the form if you are wondering:
<form action="POST">
{% csrf_token %}
<div class="row">
{{ existing_bendrija.name | as_crispy_field }}
</div>
<div class="row">
{{ existing_bendrija.address | as_crispy_field }}
</div>
<div>
<p>
<button type="submit" class="btn btn-success">Submit</button>
</p>
</div>
</form>
any suggestions? because I have 0 idea why the id is getting the request method and not the model id
edit:
urlpatterns = [
path('', views.index, name='home'),
path('bendrijos/', views.bendrijos_view, name='bendrijos'),
path('add_bendrija/', views.add_bendrija_view, name='add_bendrija'),
path('bendrijos_turinys/<bendrija_id>', views.bendrijos_turinys_view, name='bendrijos_turinys'),
path('darbas_form/<bendrija_id>', views.add_darbas_view, name='darbas_form'),
path('ataskaita_form/<bendrija_id>', views.add_ataskaita_view, name='ataskaita_form'),
path('edit_bendrija/<bendrija_id>', views.edit_bendrija_view, name='edit_bendrija'),
]

I found my own mistake, in the form html element I have action="POST", it should be method="POST"
so it should be:
<form method="POST">

Related

Django Form after redirect is empty after successfully submitting a form

I have a template called courses for the url http://127.0.0.1:8000/gradebook/courses/. This template lists existing Course objects loads the CourseForm form. The form successfully creates new objects.
If I go to the addassessment template with url http://127.0.0.1:8000/gradebook/addassessment/7/, it correctly loads the AssessmentForm. I want to submit this form and then return to the previous courses template. The AssessmentForm submits and the object is saved, but when it redirects back to the courses template, the CourseForm does not load. The courses template loads, the expect html loads correctly other than the form fields. I notice that the url for this page is still http://127.0.0.1:8000/gradebook/addassessment/7/ and not ../gradebook/courses/.
app_name = 'gradebook'
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
path('signup/', SignUpView.as_view(), name='signup'),
path('courses/', views.courses, name='courses'),
path('classroom/', views.classroom, name='classroom'),
path('objective/<int:course_id>/', views.addobjective, name='addobjective'),
path('addassessment/<int:course_id>/', views.addassessment, name='addassessment'),
]
#urls.py project
urlpatterns = [
path('', TemplateView.as_view(template_name='home.html'), name='home'),
path('admin/', admin.site.urls),
path('gradebook/', include('gradebook.urls')),
path('gradebook/', include('django.contrib.auth.urls')),
]
#models.py
class Course(models.Model):
course_name = models.CharField(max_length=10)
class Classroom(models.Model):
classroom_name = models.CharField(max_length=10)
course = models.ForeignKey(Course, on_delete=models.CASCADE)
class Assessment(models.Model):
course = models.ForeignKey(Course, on_delete=models.CASCADE)
assessment_name = models.CharField(max_length=10)
objectives = models.ManyToManyField('Objective')
class Objective(models.Model):
course = models.ForeignKey(Course, on_delete=models.CASCADE)
objective_name = models.CharField(max_length=10)
objective_description = models.CharField(max_length=30)
#views.py
def courses(request):
course_list = Course.objects.order_by('course_name')
context = {'course_list': course_list}
if request.method == 'POST':
details = CourseForm(request.POST)
if details.is_valid():
course = details.save(commit=False)
course.save()
form = CourseForm(None)
context['form'] = form
return render(request, "gradebook/courses.html", context)
else:
context['form'] = details
return render(request, "gradebook/courses.html", context)
else:
form = CourseForm(None)
context['form'] = form
return render(request, "gradebook/courses.html", context)
def addassessment(request, course_id):
course_list = Course.objects.order_by('course_name')
this_course = Course.objects.get(id=course_id)
objectives = Objective.objects.filter(course=this_course).order_by('objective_name')
context = {'this_course': this_course}
context['objectives'] = objectives
context['course_list'] = course_list
if request.method == 'POST':
form = AssessmentForm(request.POST)
if form.is_valid():
assess = form.save(commit=False)
# save the course that the objective belongs to
assess.course = this_course
assess.save()
form.save_m2m()
return render(request, "gradebook/courses.html", context)
else:
context['form'] = form
return render(request, "gradebook/addassessment.html", context)
else:
form = AssessmentForm(None)
form.fields["objectives"].queryset = Objective.objects.filter(course=this_course)
context['form'] = form
return render(request, "gradebook/addassessment.html", context)
#forms.py
class AssessmentForm(ModelForm):
class Meta:
model = Assessment
fields = ('assessment_name', 'objectives',)
class CourseForm(ModelForm):
class Meta:
model = Course
fields = ["course_name"]
def clean(self):
super(CourseForm, self).clean()
course_name = self.cleaned_data.get('course_name')
if course_name and Course.objects.filter(course_name__iexact=course_name).exists():
self.add_error(
'course_name', 'A course with that course name already exists.')
if len(course_name) > 10:
self.add_error(
'Your course name cannot be longer than 10 characters')
return self.cleaned_data
#courses template: course.html
<div class="container">
<div class="row">
<div class="twelve columns">
<h1>Courses</h1>
</div>
</div>
<div class="row">
<div class="col-md-12">
{% if course_list %}
<ul>
{% for course in course_list %}
<li><div class = "row">
<div class = "col-md-3">
{{ course.course_name }}
</div>
</div></li>
{% endfor %}
</ul>
{% else %}
<p>No Courses are available.</p>
{% endif %}
</div>
</div>
<div class="row">
<div class="col-md-3">
<p>Create a new course</p>
</div>
<div class="col-md-3">
<form action="{% url 'gradebook:courses' %}" method="post">
{% csrf_token %}
{{ form.as_p }}
<div class="form-group">
<button type="submit" class="btn btn-primary">
Submit
</button>
</div>
</form>
</div>
</div>
</div>
#addassessment template: addassessment.html
<div class="container">
<div class="row">
<div class="twelve columns">
<h1>{{ this_course }}</h1>
</div>
</div>
<div class="row">
<div class="col-md-3">
<p>Add an assessment to your class</p>
</div>
<div class="col-md-3">
<div class="form-group">
<form action="" method="post">
{% csrf_token %} {{ form|crispy }}
<div class="form-group">
<button type="submit" class="btn btn-secondary">Submit</button>
</div>
</form>
</div>
</div>
</div>
</div>
There are no error messages.
When you submit your assessment form at http://127.0.0.1:8000/gradebook/addassessment/7/ your sending a post request back to your addassessment view function to process your form which you know. The url will still be the same as a result, which is what you are seeing.
I would suggest against returning the courses template if your assessment form is valid in the way you have written
#inside addassessment view function
return render(request, "gradebook/courses.html", context)
If you are just wanting to redirect to the courses view upon successfully saving the assessment form I suggest using the redirect shortcut.
# add to your import
from django.shortcuts import render, redirect
#inside addassessment view function - replacing "return render(request, "gradebook/courses.html", context)"
return redirect(courses)
This will send your request object to the courses view function. The redirect will use a GET action instead of a post so you'll just see what you would normally at http://127.0.0.1:8000/gradebook/courses/. This will also be the url!

Form wont appear in admin side of website and confused as to why and wondering if someone else could see why

models.py
class Contact(models.Model):
BookID = models.CharField(max_length=30)
BookTitle = models.CharField(max_length=30)
Author = models.CharField(max_length=35)
UploadImage =
models.ImageField(upload_to='ContactImg')
def __str__(self):
return self.BookId
forms.py
class ContactForm(forms.Form):
BookID=forms.CharField(max_length=30,required=True)
BookTitle=forms.CharField(max_length=30,required=True)
Author=forms.CharField(max_length=35,required=True)
UploadImage=forms.ImageField()
class Meta:
model = Contact
fields = ('BookID', 'BookTitle', 'Author','UploadImage')
Views.py
def ContactUs(request):
context_dict = {}
if request.user.is_authenticated:
context_dict['logged_in'] = True
else:
context_dict['logged_in'] = False
user_form=ContactForm()
if request.method == 'POST':
user_form = ContactForm(request.POST)
if user_form.is_valid():
# we load our profile instance
Contact.BookId = user_form.get('BookId')
Contact.BookTitle = user_form.get('BookTitle')
Contact.Author= user_form.get('Author')
Contact.UploadImage= user_form.get('UploadImage')
Contact.save()
return redirect('readingTime:home')
else:
# Invalid form
# messages.error(request, 'Form contains errors. Double check')
print(user_form.errors)
messages.error(request, 'Form contains errors. Double check')
# user_form = user_form.errors
# user_form = RegisterForm()
else:
# Blank form since we do not have an HTTP POST
user_form = ContactForm()
return render(request,"readingTime/ContactUs.html",context=context_dict)
Html
{% extends 'readingTime/base.html' %}
{% load staticfiles %}
{% block style_css %}
<link rel="stylesheet" type="text/css" href="{% static 'css/ContactUs.css' %}"
xmlns="http://www.w3.org/1999/html"/>
{% endblock %}
{% block navigation_bar %}
<div class="navigation-bar">
home
{% if logged_in %}
Sign Out
My account
User Polls
{% else %}
Register
Sign In
Poll Results
{% endif %}
</div>
{% endblock %}
{% block body_block %}
<div class="main" >
<h1>Contact Us</h1>
<div class="main2">
<form id="user_form" class="contact-form" method="post" action="{% url 'readingTime:ContactUs'
%}" enctype="multipart/form-data">
<div class="contact-container">
<h2>Request To Add A Book</h2>
{% csrf_token %}
Bookd Id (ISBN) <input type="text" name="BookID" value="" size="30" />
<br />
Book Title <input type="text" name="BookTitle" value="" size="50" />
<br />
Author(Full Name) <input type="text" name="Author" value="" size="30" />
<br />
Book Cover(Optional)<input type="file" id="UploadImage" name="UploadImage">
<br/>
<!-- Submit button-->
<div>
<button type="submit" class="submit-button">Send Request</button>
</div>
</div>
</form>
<h4>Popular Questions</h4>
<ul>
<li> <div class="Question">How To Sign In ?</br></br>
<Answer>Click on the sign in page button and enter your log in details</Answer></div>
</li>
</br></br></br>
<li> <div class="Question">How to edit my profile?</br></br>You need to be first signed in and then you can navigate to myAccount and click edit profile to change your details</br></div></li>
</br></br></br>
<li> <div class="Question">How to Sign out of my account?</br></br>You need to navigate to the sign out button at the top and press it to sign out</div></li>
</br></br></br>
<li> <div class="Question">How to register for an account?</br></br>Click on the register button at the top of the page in order and then enter your details or go to the sign in page and sign up to register there</div></li></ul>
<!-- action indicates where to send the form when submitted -->
</div>
</div>
{% endblock %}
{% block footer %}
{% endblock %}
I am wondering as to why it wont let me send the information inside the form to admin side of the page as it lets me automaticaly a manual from into the admin side but wont let me recieve the data from the form i create for the contact us page and was wondering if anyone has any ideas as to why this is ?
The way you have done this has a lot of errors.
Lets start again:
Your model looks fine.
forms.py:
class ContactForm(forms.ModelForm):
class Meta:
model = Contact
fields = '__all__'
views.py
from .forms import ContactForm
def ContactUs(request):
if request.user.is_authenticated:
logged_in = True
else:
logged_in = False
if request.method == 'GET':
user_form=ContactForm()
elif request.method == 'POST':
user_form = ContactForm(request.POST)
if user_form.is_valid():
user_form.save()
return redirect('readingTime:home')
context = {
'logged_in': logged_in,
'user_form': user_form
}
return render(request, "readingTime.html", context)
readingTime.html
<form id="user_form" class="contact-form" method="POST" action="{% url'readingTime:ContactUs'%}" enctype="multipart/form-data">
<div class="contact-container">
<h2>Request To Add A Book</h2>
{% csrf_token %}
{{ user_form }}
<!-- Submit button-->
<div>
<button type="submit" class="submit-button">Send Request</button>
</div>
</div>

In Django update-view instance is not pre-filled in the form

Update-form is not filled in with the instance of the object: when I press the the button that leads me to the update-view page it has no data, however if I copy the url while being on that page and pass it to a new tab - it immediately has the data.
Check the code:
Model:
class ExpenseName(Time):
name = models.CharField(max_length=20)
user = models.ForeignKey(User, on_delete=models.CASCADE)
budget_default = models.IntegerField(null=True, blank=True)
Backend:
#login_required
def update_expense(request, id):
item = ExpenseName.objects.get(id=id)
if item.user == request.user:
if request.method == 'POST':
form = NewFieldForm(request.POST, instance=item)
if form.is_valid():
form.save()
return redirect('home')
else:
form = NewFieldForm(instance=item)
else:
raise Http404('You are not allowed to see this')
context = {
'form': form
}
return render(request, 'expenses/update.html', context)
Path
path('<int:id>/update/', update_expense, name='update-field')
URL
<form method="POST" action="{% url 'update-field' item.id %}">
{% csrf_token %}
<button id="my-button2" type="submit"></button>
</form>
So, if I click on the button above I get to the page with this url -http://127.0.0.1:8000/expenses/9/update/, however when clicking the button and getting to the page there is not data prefilled. If I while being on that same page copy this http://127.0.0.1:8000/expenses/9/update/ and pass it to another tab - it prefills immediately.
Frontend:
{% extends 'expenses/base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div class="row h-100 align-items-center justify-content-center">
<div class="col-6 text-center" style="height:250px; width: 100px; padding-top: 30px; background-color: #4db8ff; border-radius: 10px;">
<form method="POST"> {% csrf_token %}
Name of the expense:<div>{{ form.name }}</div>
Budget: <div>{{ form.budget_default }}</div>
<div><button class="btn btn-sm btn-dark mt-2 text-center" type="submit">Update</button></div>
<a class="text-dark" style="font-size: 13px;" href="{% url 'home' %}">Cancel</a>
</form>
</div>
</div>
{% endblock content %}
Form:
class NewFieldForm(forms.ModelForm):
class Meta:
model = ExpenseName
fields = [
'name',
'budget_default'
]
labels = {
'name': '',
'budget_default': '',
}
I really do hope someone can help me understand what the issue is. Can't complete the project without solving it.

How do you render form from views in template without model?

I have a problem with my Django Code.I'm trying to render a form from views to template and i'm just seeing the submit button. I noticed that we can use forms dynamically by introducing it like this {{ form }}, but when I use it, I just see the "submit" button on the page(Sorry I don't know how to upload a local image here). I join my four files: views.py, home.html, forms.py and urls.py
Thank you in advance
home.html
<form method="POST" novalidate action="/config">
{% csrf_token %}
<fieldset>
<legend class="border-bottom mb-4">Home</legend>
{{ form.as_p }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Sign Up</button>
</div>
</form>
views.py
def inputHome(request):
form = InputHomeForm()
if request.method == 'POST':
form = InputHomeForm(request.POST)
if form.is_valid():
mk = form.cleaned_data['mk']
return HttpResponseRedirect('blog-config')
else:
form = InputHomeForm()
return render(request, 'blog/home.html', {'form': form})
forms.py
class InputHomeForm(forms.Form):
mk = forms.CharField(widget=forms.TextInput(attrs={'class': 'special'}))
urls.py
urlpatterns = [
path('home/', blog_views.home, name='blog-home'),
]
I don't have an error message so i don't have an idea of the problem.
You are missing form tag in html.
HTML should be,
<form method='post'>
{% csrf_token %}
<fieldset>
<legend class="border-bottom mb-4">Home</legend>
{{ form.as_p }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Sign Up</button>
</div>
</form>
Slightly unrelated (cf Nishant's answer for the main issue), but here:
if request.method == 'POST':
form = InputHomeForm(request.POST)
if form.is_valid():
mk = form.cleaned_data['mk']
return HttpResponseRedirect('blog-config')
else:
form = InputHomeForm()
In the else clause, you're replacing the bound invalid form (which carries the validation errors) with an unbound form, so you'll never get the error messages. Just remove the whole else clause.

User can post comment only after login in Django

I'm coding a news website,I want the user can submit the comment of the news only after they have logged in,if not,the website will return to login.html.
Now I have made it that only the user who have logged in can submit a comment,the issue is once I log off and submit a comment the error says:
Cannot assign "<SimpleLazyObject: <django.contrib.auth.models.AnonymousUser object at 0x10fed10b8>>": "NewsComments.user" must be a "UserProfile" instance.
Note:I have rewrote the User models and rename it UserProfile .It works very well.
Here is my news/views.py:
def newsDetailView(request, news_pk):
news = News.objects.get(id=news_pk)
title = news.title
author = news.author_name
add_time = news.add_time
content = news.content
category = news.category
tags = news.tag.annotate(news_count=Count('news'))
all_comments = NewsComments.objects.filter(news=news)
comment_form = CommentForm(request.POST or None)
if request.method == 'POST' and comment_form.is_valid():
comments = comment_form.cleaned_data.get("comment")
comment = NewsComments(user=request.user, comments=comments, news=news)
comment.save()
return render(request, "news_detail.html", {
'title': title,
'author': author,
'add_time': add_time,
'content': content,
'tags': tags,
'category': category,
'all_comments': all_comments,
'comment_form': comment_form
})
Here is my news.detail.html
<form method="POST" action="">{% csrf_token %}
<div class="form-group">
<label for="exampleFormControlTextarea1"><h5>评论 <i class="fa fa-comments"></i></h5></label>
<textarea id="js-pl-textarea" class="form-control" rows="4"
placeholder="我就想说..." name="comment"></textarea>
<div class="text-center mt-3">
<input type="submit" id='js-pl-submit' class="btn btn-danger comment-submit-button" value='Submit'>
</input>
</div>
</div>
</form>
Here is my urls.py:
path('-<int:news_pk>', newsDetailView, name="news_detail"),
You could use djangos login-required-decorator.
#login_required
def newsDetailView(request, news_pk):
...
EDIT to expand the idea from my comments.
You could have two views, one with the login_required decorator. (You could also use class-based-views (CBV) if you prefer)
def view_news_details(request, news_pk):
...
#login_required
def post_comments(request, news_pk):
...
Each view would have their own url:
url(r'^(?P<news_pk>[0-9]+)/$', views.view_news_details, name='view-details'),
url(r'^(?P<news_pk>[0-9]+)/comment/$', views.post_comments, name='comment'),
Then you can have only one template but with conditional rendering. This template will be rendered by the view views.view_news_details, but the form will send its data to the other view (note the forms action attribute).
... display the news details here ...
{% if request.user.is_authenticated %}
<form method="POST" action="{% url 'comment' news_instance.pk %}">
... here goes the content of the form ...
</form>
{% endif %}
Redirect the user to your login view before let him submit any data in your views.py :
# Codes here
if request.method == 'POST': # We separe those two "if statements", because
# We want to redirect the user to login even if the form is not valid, User can bypass your security concern
# For Django < 2.0, use it with () if request.user.is_authenticated():
if request.user.is_authenticated:
return redirect("login_url_name") # Or HttpResponseRedirect("login_url")
if comment_form.is_valid():
comments = comment_form.cleaned_data.get("comment")
# Rest of codes
Important
In your template, give access to the form to only authenticated users
{% if request.user.is_authenticated %}
<form method="POST" action="">{% csrf_token %}
<div class="form-group">
<label for="exampleFormControlTextarea1"><h5>评论 <i class="fa fa-comments"></i></h5></label>
<textarea id="js-pl-textarea" class="form-control" rows="4"
placeholder="我就想说..." name="comment"></textarea>
<div class="text-center mt-3">
<input type="submit" id='js-pl-submit' class="btn btn-danger comment-submit-button" value='Submit' />
</div>
</div>
</form>
{% endif %}
You can check whether the requested user is logged-in or not by user.is_authenticated() method, which returns a boolean value.
Try the following snippet,
def newsDetailView(request, news_pk):
# code
if request.method == 'POST' and comment_form.is_valid():
if not request.user.is_authenticated():
return HttpResponse("Please do login")
comments = comment_form.cleaned_data.get("comment")
comment = NewsComments(user=request.user, comments=comments, news=news)
comment.save()
return render(request, "news_detail.html", {
'title': title,
'author': author,
'add_time': add_time,
'content': content,
'tags': tags,
'category': category,
'all_comments': all_comments,
'comment_form': comment_form
})