Passing parameters to Django view through url - python

I am trying to create a formset that captures a parameter from the url to prefill one of the fields. The form is displaying correctly and at the correct address, but after clicking "submit" the page redirects to "/correction/" instead of the intended /correction/A07686+dwdID19, and the form does not save. What might be the issue?
In models.py:
class correction(models.Model):
corrected_word = models.ForeignKey(item)
correction_author = models.ForeignKey(User)
correction_made = models.IntegerField(u'correction_made', choices=CORRECTION_CHOICES)
correction_word = models.CharField(u'correction_word', max_length=200, blank=True, null=True)
time = models.DateTimeField(auto_now_add=True)
approved = models.IntegerField(u'approved', choices=APPROVAL_CHOICES, blank=True, null=True)
def __unicode__(self):
return str(self.time)
In views.py:
def submit_corr(request, bdword):
if hasattr(request, 'user') and request.user.is_authenticated():
word = item.objects.filter(file_position=bdword)[0]
CorrFormSet = inlineformset_factory(item, correction, fields=['correction_made', 'correction_word','correction_author'], can_delete=False, extra=1)
form = CorrFormSet(request.POST, request.FILES, instance=word, initial=[{'correction_author': request.user,}])
if request.method == 'POST':
if form.is_valid():
for entry in form:
entry.save()
else:
form = CorrFormSet(instance=word, initial=[{'correction_author': request.user,}])
return render(request, "correctionform.html", {"form": form,"word": word})
In urls:
url(r'^correction/(?P<bdword>.*)$', 'english.views.submit_corr'),
In the template:
Submit correction</th>
Thanks in advance!

Submit correction doesn't submit a form because it's a link and when you press a link, this sends a request with a GET method to the server so never enter to if request.method == 'POST': .
Please try something like
<form action="/correction/{{word.file_position}}" method="POST">
{# your inputs fields#}
<button type="submit">Submit correction</button>
</form>
I hope to be useful. Regards

Related

My view doesn't save the instance from Form in Djagno

I'm trying make a comment section for my Q&A project.I made the model for comment , the form part in question_detail.html an , also the QuestionCommentForm() in form.py .
model.py
class QuestionComment(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE)
question =
models.ForeignKey(Question,on_delete=models.CASCADE)
created_date = models.DateTimeField(auto_now_add= True)
body = models.CharField(max_length=200, null= True ,
blank = True, default ='')
def __str__(self):
return str(self.body)
forms.py
{%if c_form%}
<form method="POST" action= "{% usl 'blog:question-commet' question.id >{% csrf_token %}
{{c_form.media}}
{{ c_form.as_p}}
<button type = "submit" , name = "question_id", value = "{{question.pk}}", class ="btn btn-secondary btn-sm">submit comment</button>
views.py
#api_view(['POST','GET'])
def question_comment(request, *args, **kwargs):
form = QuestionCommentForm()
print('finction comment started'*20)
if request.method == 'POST':
c_form = QuestionCommentForm(request.POST)
if c_form.is_valid():
new_comment = c_form.save(commit=False)
new_comment.refresh_from_db()
c_form.instance.user = request.user
question = Question.objects.get(id = request.POST.get('question_id')
new_comment.question = question
new_comment.bldy =c_form.cleaned_data.get('body')
new_comment.save()
context['c_form'] = c_form
return render(request, 'blog/question_detail.html',context)
class QuestionDetail(DetailView):
template_name = 'blog/question_detail.html'
model = Question
context_object_name = 'question'
count_hit = True
def get_queryset(self):
return Question.objects.filter(id = self.kwargs['pk'])
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
c_form = QuestionCommentForm()
context = super(QuestionDetail,self).get_context_data(**kwargs)
self.obj= get_object_or_404(Question, id = self.kwargs['pk'])
self.object.save()
self.object.refresh_from_db()
answers = Answer.objects.filter (question_id = self.obj.id).order_by('-created_date')
liked =self.obj.like.filter(id =self.request.user.id).exists()
print('liked in class question not checked still' *10)
comments= QuestionComment.objects.filter(question = self.kwargs['pk'])
context['comments']= comments
context["answers"]=answers
context["liked "] = liked
context['c_form'] = c_form
return context
def post(request, *args, **kwargs):
print('post started'*100)
c_form = QuestionCommentForm()
c_form = QuestionCommentForm(request.POST)
if c_form.is_valid():
new_comment = c_form.save(commit=False)
new_comment.refresh_from_db()
new_comment.user = request.user
new_comment.question = c_form.cleaned_data.get('question_id')
new_comment.bldy =c_form.cleaned_data.get('body')
new_comment.save()
context['c_form'] = c_form
else:
c_form= QuestionCommentForm()
return render(request, 'blog/question_detail.html',context)
url.py
...
path('question-comment/<int:pk>/', question_comment, name = 'question-comment'),
]
in my view, first I tried to use a another function to handle the comment, got no result and made a def post()
in the class QuestionDetial() , and still the form shows up but when I type something and hit the button , it refresh the page and nothing saves . I have already saved a comment using admin and it appears in the question-detail page. used print to find the bug, but it seems the post() in class and the question_comment() not being recall. searched a lot but no answer. (BTW I get no error except the NoReverseMatch that I fixed)
You never save the model object (not by the form, nor by the view). Furthermore the name of the method is 'POST', not 'Post':
#api_view(['POST','GET'])
def question_comment(request, *args, **kwargs):
form = QuestionCommentForm()
print('finction comment started'*20)
if request.method == 'POST':
c_form = QuestionCommentForm(request.POST)
if c_form.is_valid():
c_form.instance.user = request.user
c_form.save()
context = {'c_form': c_form }
return render(request, 'blog/question_detail.html',context)
ok , the problem was that I had two form-tags in question_detail template and buy adding comment form in the end of the template had 3 , but the problem was when I pressed the submit comment button the terminal showed this message
"POST /create-like/blog/answer/18/ HTTP/1.1" 302 0
which was the form I had made for like function .(while my url was question-comment)
I accidentally forgot to close the like-form tag in template. so all I needed was putting a
</form>
after the form block .
thank's Willem Van Onsem. it solved my post method error.
and these were very helpful
Proper way to handle multiple forms on one page in Django
How can I build multiple submit buttons django form?

User Feedback through Django Email

I have an app, in which the main User adds a sub user and sends him an email. I want the sub user to have a button in the email template that would lead him/her to a Feedback form. That feedback form's url must have the user's name in it as it gives a personal touch. But I am not understanding how do I pass the sub user data and save the feedback data against the data. I will create a scenario to make you guys understand better.
1. There is a main user Chris, Chris adds a sub user Leon in his email list. (P.S both are Resident .Evil characters).
2. Chris sends an email to Leon, Leon will receive the email and if he want he can give a feedback by clicking the feedback button in email.
3. If Leon clicks the button he will be redirected to a page where the url could be something like this (www.feedback/Leon.com), there will be form where Leon will add his review and submit.
The problem is how do I save Leon's feed back in the FeedBack model through the email form against his information from the sub user model (PersonData).
models.py
class FeedBack(models.Model):
feedback = models.TextField('Feedback')
user_feedback = models.ForeignKey(PersonData)
class PersonData(models.Model):
user_relation = models.ForeignKey(User)
person_first_name = models.CharField("First Name", max_length=25)
person_last_name = models.CharField("last Name", max_length=25)
person_email = models.EmailField("Email", max_length=512)
views.py
# class FeedBackCreateView(CreateView):
# model = FeedBack
# template_name = "userfiles/FeedBack.html"
# def form_valid(self, form):
# obj = form.save(commit=False)
# obj.user_feedback_id = self.request.persondata_id
# obj.save()
# return redirect("Home-Page")
def feedback(request, username):
person_data = PersonData.objects.get(person_first_name=username)
item = FeedBack.objects.all().filter(user_feedback=person_first_name)
form = FeedBackForm
if request.method == 'POST':
if form.is_valid():
form.save(commit=False)
profile.employee_name = user
profile.save()
return redirect('Home-Page')
context = {'all_item': all_item}
return render(request, 'userfiles/AlbumPicsList.html', context)
------------------------------------------------------------------
#This View is from another app called salami. This sends the email
------------------------------------------------------------------
def send_email(request, s_id, pr_id):
salami_data = SalamiCalculator.objects.get(id=s_id)
person_data = PersonData.objects.get(id=pr_id)
context = {'salami_data': salami_data,
'person_data': person_data}
subject = "Thank You"
email_from = settings.EMAIL_HOST_USER # email from
to_email = [person_data.person_email] # email to
msg = EmailMultiAlternatives()
msg.from_email = email_from
msg.to = to_email
msg.subject = subject
msg.body = salami_data.thankyou_msg
html_body = render_to_string("salamifiles\email-thanks.html")
html_template = get_template("salamifiles\email-thanks.html")
html_content = html_template.render(context)
msg.attach_alternative(html_content, "text/html")
msg.send()
messages.success(request, ("Email Sent !!"))
return render(request, 'salamifiles\email-thanks.html', context)
url.py
url(r'^(?i)Feedback/(?P<user_feedback>\w+)/$',
AlbumPicturesDetail.as_view(), name='Album-Pictures-View'),
==============================================
Salami URL
==============================================
url(r'^Congratsmail/(?P<s_id>[0-9]+)/(?P<pr_id>\d+)/$',
views.send_email, name='Congrats-EMAIL'),
forms.py
class FeedBackForm(forms.ModelForm):
class Meta:
model = FeedBack
fields = ("feedback")
email.html
Have Not Yet modified the email template by adding the button
Email Sending template
{% for i in items %}
<a href={% url 'Congrats-EMAIL' s_id=i.id pr_id=i.realted_person.id %}>Send Mail</a>
{% endfor %}
=========================================================================
I expect when Chris send Leon the email, Leon by clicking on the button gets redirected to a page where the URL has his name and the form already is knows he's Leon so that it saves the data against his id/name.
I do not understand why you cannot do
class FeedBack(models.Model):
feedback = models.TextField('Feedback')
user_feedback = models.ForeignKey(PersonData, related_name="received_feedbacks")
giver_feedback = models.ForeignKet(PersonData, related_name="given_feedbacks")
I agree with #HenryM, You can add an extra field for relating to PersonData.
class FeedBack(models.Model):
feedback = models.TextField('Feedback')
user = models.ForeignKey(PersonData, related_name="received_feedbacks")
giver = models.ForeignKet(PersonData, related_name="given_feedbacks")
Then, you can use it like this:
from django.contrib.auth.decorators import login_required
#login_required
def feedback(request, username):
person_data = PersonData.objects.get(person_first_name=username)
item = FeedBack.objects.all().filter(user_feedback=person_first_name)
form = FeedBackForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
feedback = form.save(commit=False)
feedback.user = person_data
feedback.giver = PersonData.objects.get(user_relation=request.user)
feedback.save()
profile.employee_name = user
profile.save()
return redirect('Home-Page')
context = {'form': form}
return render(request, 'form_which_renders_feedbackform.html', context)
I would recommend using OneToOne relation instead of ForeignKey for user_relation field in PersonData. So that you can simply access it via request.user.persondata.

The view didn't return an HttpResponse object when use redirect()

I tried creating model form to add new record to my models in django, but I got this error:
The view post.views.add_job_resume didn't return an object. It returned None instead.
this is my files(Notice that in this file I have more codes than what I write here):
view.py
def add_job_resume(request):
if request.method=="POST":
form = AddJobForm(request.POST)
if form.is_valid():
job_resume = form.save(commit=False)
job_resume.user= request.user
job_resume.save()
return redirect('view_job_resume')
else:
form = AddJobForm()
return render(request, 'education/job_research_education_records/job_resume/add_job_resume.html', {'form': form})
forms.py
class AddJobForm(ModelForm):
class Meta:
model = JobRecord
fields = [
'title',
'explains',
'post',
'organization',
'time_start',
'time_end',
'upload_url',
]
models.py
class JobRecord(models.Model):
user = models.ForeignKey(User, on_delete=models.PROTECT)
title = models.TextField(max_length=250, blank=False)
explains = models.TextField(max_length=500, blank=True)
post = models.TextField(max_length=100, blank=False)
organization = models.TextField(max_length=100, blank=False)
time_start = models.TextField(max_length=100)
time_end = models.TextField(max_length=100)
upload_url = models.FileField(upload_to='job-resume-files/')
def __str__(self):
return self.title
add_job_resume.html
<form method="post" >
{% csrf_token %}
{{form.as_p }}
<button type="submit" class="btn btn-info">add</button>
</form>
urls.py
urlpatterns = [
path('edu/resume/job/', views.view_job_resume, name='view_job_resume'),
path('edu/resume/job/add', views.add_job_resume, name='add_job_resume')]
I search a lot for this error but I can't solve that! What is going on?
This has nothing to do with the redirect(..) itself. You just forgot a code path. It is possible that the method is indeed POST, but that the form is not valid. So the condition in the first if is satisfied, but the condition in the second if is not. Right now, your view will return nothing (hence return None) for this situation.
It is common to simply rerender the template, but now with the invalid form, such that the form can show the errors, like:
def add_job_resume(request):
if request.method=="POST":
form = AddJobForm(request.POST)
if form.is_valid():
job_resume = form.save(commit=False)
job_resume.user= request.user
job_resume.save()
return redirect('view_job_resume')
else:
form = AddJobForm()
# Not placed under the else
return render(
request,
'education/job_research_education_records/job_resume/add_job_resume.html',
{'form': form}
)
Notice that the render is not put under the else part. Indeed regardless whether the method is POST and the form is invalid, or the method is not POST, we render the page and respond with the rendered page.
Redirecting is not the problem. The problem is that your form is not valid, and the view does not turn anything if that happens
You should unindent the last line one level, so that it catches this case.

Django image form isn't saving the image

I have a form that involves uploading a profile picture. I have it working so that I can upload images in the /admin/ interface and display them correctly, but I cannot get my Modelform to save the image.
Here is what I have:
models.py
class Candidate(models.Model):
UserID = models.ForeignKey(User, on_delete=models.CASCADE)
ElectionID = models.ForeignKey(Election, on_delete=models.CASCADE)
Bio = models.CharField(max_length=500, blank=True)
ProfilePicture = models.ImageField(upload_to="profilepics/", null=True, blank=True)
forms.py
class AddCandidateForm(forms.ModelForm):
class Meta:
model = Candidate
fields = ['ElectionID', 'Bio', 'ProfilePicture']
cand_reg.html (Template)
{% block content %}
<h1>Register as a candidate</h1>
<form method="POST" class="post-form">
{% csrf_token %}
<h2>Select an election:</h2><br>
{{form.ElectionID}}<br>
<h2>Enter your bio:</h2><br>
{{form.Bio}}<br>
<h2>Upload a profile picture:</h2><br>
{{form.ProfilePicture}}<br>
<button type="submit">Register</button>
</form>
{% endblock %}
When I try the view function like so I get the error:
MultiValueDictKeyError at /register/
"'ProfilePicture'"
views.py
def add_candidate(request):
if request.method == 'POST':
form = AddCandidateForm(request.POST, request.FILES)
if form.is_valid():
candidate = form.save(commit=False)
candidate = request.FILES['ProfilePicture']
candidate.UserID = request.user
candidate.save()
return redirect('/home/')
else:
form = AddCandidateForm()
return render(request, 'cand_reg.html', {
"form": form
})
views.py
When I remove the offending line, the error goes away.
def add_candidate(request):
if request.method == 'POST':
form = AddCandidateForm(request.POST, request.FILES)
if form.is_valid():
candidate = form.save(commit=False)
# candidate = request.FILES['ProfilePicture']
candidate.UserID = request.user
candidate.save()
return redirect('/home/')
else:
form = AddCandidateForm()
return render(request, 'cand_reg.html', {
"form": form
})
However, this doesn't actually save the image, so when I try to render it in a separate template, I get an error then.
Can anyone help me understand why the image isn't uploading?
Thanks in advance :)
You must set the ProfilePicture attribute of the model and not the instance itself (candidate = request.FILES['ProfilePicture']).
Change to:
candidate = form.save(commit=False)
candidate.ProfilePicture = request.FILES['ProfilePicture']
candidate.UserID = request.user
candidate.save()
Change your HTML form to accept files as well. Change to: <form method="POST" enctype="multipart/form-data" class="post-form">. When a form includes file inputs (<input type="file" />), then it must be encoded differently than it used when it includes only text. More here. If you right-click and inspect the {{form.ProfilePicture}} you'll see that this is actually a file input.
Extra one:
Please, do not name your class attributes (ProfilePicture, UserID etc) in PascalCase. Use snake_case instead (profile_picture, user_id etc).

how to to display the category user created by the current user on every page

as title indicates I'm trying to send the name of a category user created by the current user on every page. My initial attempt was simply
{% if user.is_authenticated == category.author %}
{{category.name}}
{% endif %}
but this only displays the category in a certain page, while I want to display this in the navbar which I have it included for the every page. So I thought I should do category = models.foreignkey('category') in my user model but got told I should set a queryset in a template context processor. which I'm not sure it's the best way to do.
Can someone please direct me how I should do such matter?
here's my code
class Category(models.Model):
name = models.CharField(max_length=128, unique=True)
description = models.TextField()
author = models.ForeignKey(settings.AUTH_USER_MODEL)
and in my views.py
#login_required
def add_category(request):
if not request.user.is_superuser and Category.objects.filter(author=request.user).exists():
return render(request,'main/category_already_exists.html')
if request.method == 'POST':
category = Category(author=request.user)
form = CategoryForm(request.POST, request.FILES, instance=category)
if form.is_valid():
form.save(commit=True)
return redirect('category', category_name_url=category.name)
else:
form = CategoryForm()
context = {
"form":form
}
return render(request, 'main/add_category.html',context)
and this is my simplified category view
def category(request, category_name_url):
category_name = decode_url(category_name_url)
category = Category.objects.get(name=category_name)
context = {
"category":category,
}
return render(request, "main/category.html", context)
and this is my model for my user
from userena.models import UserenaBaseProfile
class MyProfile(UserenaBaseProfile):
user = models.OneToOneField(User, unique=True, verbose_name=_('user'), related_name='my_profile')
Perhaps you should write your own context processor and include it in settings. Link to docs https://docs.djangoproject.com/en/dev/ref/templates/api/#context-processors
Definition from Django docs:
"Context processors are functions that receive the current HttpRequest as an argument and return a dict of data to be added to the rendering context.
Their main use is to add common data shared by all templates to the context without repeating code in every view."
You can add this information in request.session. You can do this like this:
Suppose your login view is this:
def login(request):
# Do login stuff
if user.is_active():
request.session['categories'] = [ c.name for c in Category.objects.filter(author=request.user)] # add to the session
return redirect('/somepage')
Display this data in every page like this:
{% for c in request.session.categories %}
{{ c }}
{% endfor %}
And update the category list every time the a new category is added like this:
#login_required
def add_category(request):
if not request.user.is_superuser and Category.objects.filter(author=request.user).exists():
return render(request,'main/category_already_exists.html')
if request.method == 'POST':
category = Category(author=request.user)
form = CategoryForm(request.POST, request.FILES, instance=category)
if form.is_valid():
form.save(commit=True)
request.session['categories'] = [ c.name for c in Category.objects.filter(author=request.user)]
return redirect('category', category_name_url=category.name)
else:
form = CategoryForm()
context = {
"form":form
}
return render(request, 'main/add_category.html',context)

Categories