How to use self page database update in Django? - django

I have a question on my homepage that the user should answer through radio buttons. The user should press the submit button to send the answer, so basically it is a SELF PAGE submission. The user should not go to another page after submitting the answer but should remain on the same home page. Though I looked up some earlier questions, the code did not work out.
I have created the TEMPLATE DIRECTORY under the root folder and under this directory, there is a 'pages' folder that has the index.html (homepage) inside which I am invoking the form
The form code in the index.html page.
<form action = "?" method = "POST">
I want to know what function should I write in the views. Since the form action does not call a named view I am not able to figure out how I should define the view that updates the data.
def WHAT NAME SHOULD I GIVE HERE(request):
.....other code
I am adding the following code as of 3rd May. When I use this code I get the error. I would like to state that in the form the questions.id is coming from the questions model (or table) but in the function in the views, I want to update the question.id in the questionid field in the answers model
ValueError at /updateans/updateans
Cannot assign "''": "Answers.questionid" must be a "Questions" instance.
The relevant code in the form is
<form action = "{% url 'updateans' %}" method = "POST">
<input type = "hidden" name ="questionid" value = "{{Questions.id}}">
The function in the views file is (as of now I am just trying to update one field but still getting an error - see above)
def updateans(request):
if request.method == 'POST':
questionid = request.POST["questionid"] 'variable questionid defined
print(questionid) --> even the print command shows a blank
myans = Answers(questionid=questionid)
'questionid is a field in the Answers model
myans.save()
Thanks

After Form Submission redirect the user to the same page
def answer_submit(request):
if request.method == 'POST':
name = request.POST["name"]
subject = request.POST["subject"]
email = request.POST["email"]
message = request.POST["message"]
con = Contact(name=name,subject=subject,email=email,message=message)
con.save()
# If u use messages module of django then the next line will work
messages.success(request,"Thank you for contacting us, We will get to you as soon as possible")
return redirect("home.html")
The is some thing like this u just need to redirect the user to same page

Related

Django: DropDown fails to update or refresh

Please see to the screenshot, unable to figure out the reason why the drop down don’t show the last value ‘Person 6’ while, its been populated in the html of that page.
Request help to understand the issue - Thank you!
DropDown not getting updated
DropDown not reflecting data on html
Scenario is, user clicks the ‘+’ button and a modal form opens. Form to add new party will be displayed. Once the user clicks submit button on the modal form, the modal closes and the dropdown is expected to be updated, but, instead its not getting updated though the page html reflects the new addition.
Including the view which resulted this issue.
views.py
#login_required
def AddView(request):
addForm = AddForm(request. POST or None)
if request.method == "POST":
if addForm.is_valid():
addForm.save()
response = HttpResponseRedirect(reverse('entry: entries'))
response ['HX-Trigger'] = 'Partyadded'
return response
else:
addForm = AddForm()
context = {
'addForm': addForm
}
return render(request,"entry/addNew.html",context)
Part of the template the “new_entry.html” does have the form to make new entry.
<div id='form-div' hx-trigger="load, Partyadded from: body">
{% include 'partials/new_entry.html' %}
</div>

Django update boolean field with a form

My simple web-application has two models that are linked (one to many).
The first model (Newplate) has a boolean field called plate_complete. This is set to False (0) at the start.
questions:
In a html page, I am trying to build a form and button that when pressed sets the above field to True. At the moment when I click the button the page refreshes but there is no change to the database (plate_complete is still False). How do I do this?
Ideally, once the button is pressed I would also like to re-direct the user to another webpage (readplates.html). This webpage does not require the pk field (but the form does to change the specific record) Hence for now I am just refreshing the extendingplates.html file. How do I do this too ?
My code:
"""Model"""
class NewPlate(models.Model):
plate_id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
title = models.CharField(max_length=200)
created_date = models.DateTimeField(default=timezone.now)
plate_complete = models.BooleanField()
"""view"""
def publish_plates(request,plate_id):
newplate = get_object_or_404(NewPlate, pk=plate_id)
newplate.plate_complete = True
newplate.save()
#2nd method
NewPlate.objects.filter(pk=plate_id).update(plate_complete = True)
return HttpResponseRedirect(reverse('tablet:extendplates', args=[plate_id]))
"""URLS"""
path('readplates', views.read_plates, name='readplates'),
path('extendplates/<pk>/', views.show_plates, name='showplates'),
path('extendplates/<pk>/', views.publish_plates, name='publishplates'),
"""HTML"""
<form method="POST" action="{% url 'tablet:publishplates' newplate.plate_id %}">
{% csrf_token %}
<button type="submit" class="button" value='True'>Publish</button></form>
-------Added show plates view:---------
def show_plates(request,pk):
mod = NewPlate.objects.all()
newplate= get_object_or_404(mod, pk=pk)
add2plate= Add2Plate.objects.filter(Add2Plateid=pk)
return render(request, 'tablet/show_plates.html', {'newplate': newplate,'add2plate': add2plate})
Thank you
The problem is two of your urls have the same pattern 'extendplates/<pk>/'. Django uses the first pattern that matches a url. I suppose that one of these view views.show_plates is meant to display the form and the other views.publish_plates is meant to accept the posted form data.
This means that simply both of these views should simply be a single view (to differentiate if the form is submitted we will simply check the requests method):
from django.shortcuts import redirect, render
def show_plates(request, plate_id):
newplate = get_object_or_404(NewPlate, pk=plate_id)
if request.method == "POST":
newplate.plate_complete = True
newplate.save()
return redirect('tablet:extendplates', plate_id)
context = {'newplate': newplate}
return render(request, 'your_template_name.html', context)
Now your url patterns can simply be (Note: Also captured arguments are passed as keyword arguments to the view so they should be consistent for your view and pattern):
urlpatterns = [
...
path('readplates', views.read_plates, name='readplates'),
path('extendplates/<uuid:plate_id>/', views.show_plates, name='showplates'),
...
]
In your form simply forego the action attribute as it is on the same page:
<form method="POST">
{% csrf_token %}
<button type="submit" class="button" value='True'>Publish</button>
</form>
You should avoid changing state on a get request like your view does currently.
Handle the POST request and change the data if the request is valid (ensuring CSRF protection).
def publish_plates(request,plate_id):
newplate = get_object_or_404(NewPlate, pk=plate_id)
if request.method == "POST":
newplate.plate_complete = True
newplate.save(update_fields=['plate_complete']) # a more efficient save
#2nd method
NewPlate.objects.filter(pk=plate_id).update(plate_complete=True)
return HttpResponseRedirect(reverse('tablet:extendplates', args=[plate_id]))
You could also put a hidden input in the form, or make a form in Django to hold the hidden input, which stores the plate_id value and that way you can have a generic URL which will fetch that ID from the POST data.
Now the real problem you've got here, is that you've got 2 URLs which are the same, but with 2 different views.
I'd suggest you change that so that URLs are unique;
path('extendplates/<pk>/', views.show_plates, name='showplates'),
path('publish-plates/<pk>/', views.publish_plates, name='publishplates'),

Django all-auth app, how to modify /account/profile page to display custom view

After setting up the All-Auth app, when user logs in, he gets redirected to: accounts/profile/ page which tells us that the view doesn't exist.
I'm trying to figure out what kind of thing to include there, and decided to allow the user to change their basic information.
I have a users app with a Teacher model, which is set up as follows:
class Teacher(models.Model):
user = models.ForeignKey(User, unique=True)
rate = models.CharField(max_length=200)
availability = models.BooleanField(default=False)
verified = models.BooleanField(default=False)
I want the accounts/profile/ page to show a form, containing this information. The user can edit these fields and also edit their Firstname, Lastname and Email, which belong to a different Model - User.
I can't seem to get started on this. When I created a detailed view for the profile page, I get an error saying:
No PK or SLUG provided
I want Django to change the current users info, not based on the primary key in the URL. Do I need a custom view? I've looked at [other solutions1
but they seem to be utilising the private key parameter.
What I need is a working view function, something similar to (not working):
def get_teacher_info(request):
current_user = request.user
teacher = get_object_or_404(Teacher, username=current_user.username)
return render(request, 'account/profile.html', {
'user':current_user,
'teacher': teacher,
'error_message': "The field is blank",
})
and in the accounts/urls.py I've added:
url(r"^profile/$", views.get_teacher_info, name="account_profile"),
but when I make calls like {% teacher.rate %} in the html template, I get:
Invalid block tag on line 5: 'teacher.rate'. Did you forget to register or load this tag?
The def get_teacher_info(request) function and the urls.py entry are working. Looks like the issue may be in the template. Use {{ instead of {% tags. So use {{ teacher.rate }} not {% teacher.rate %} in the template.
Redirecting to /accounts/profile/ After the login is the default behavior of Django. django-allauth is using the same default behavior from Django settings.
Now if you want to modify this default redirect url then change it to
LOGIN_REDIRECT_URL = '/custom/redirect-url'
Important Note: Without a starting / you're redirecting to a path that is appended to the CURRENT URL. You need to use a leading slash to redirect to a path that is appended to the domain root. further details on it. In short, without a starting / you will end up with
../login/callback/custom.redirect-url (appended to current url)

Django: How to return model formset in ajax and use in template

I need to dynamically add forms to my formset during runtime using ajax, for which I am referring to Dynamically adding a form to a Django formset with Ajax
I have multiple formsets on the same page with different prefixes.
My models are designed like so:
A user can have many phones. A phone can have many lines (if details are needed)
Accessing Many to Many "through" relation fields in Formsets
Once a user adds a new phone, I save the phone using ajax. The view is as follows
def addUserPhone(request, customer_id, location_id, user_id, **kwargs):
error_msg = u"No POST data sent."
context = {}
if request.is_ajax():
if request.method == "POST":
user = End_User.objects.get(id=user_id)
phone_client = PartialPhone_ClientForm(request.POST, prefix='new_client')
instance = phone_client.save()
#associate user to a phone
instance.end_user.add(user)
#Creating an empty lineFormset for a phone
LineFormSet = modelformset_factory(Line, form=Line_Form, can_delete=True)
client_lines = LineFormSet(queryset=Line.objects.none(), prefix='phone_client_'+str(instance.id))
# how to return the two objects instance and client_lines back to the template??
#format = 'json'
#mimetype = 'application/javascript'
#data = serializers.serialize(format, [instance])
#return HttpResponse(data)
#can we return as a context?? this gives me only a string "phoneline_set" in the template
context['phone'] = instance
context['line_set'] = client_lines
return HttpResponse(context)
else:
error_msg = u"Insufficient POST data (need 'Name ' and 'Telephone Number'!)"
else:
error_msg = "Non Ajax"
return HttpResponseServerError(error_msg)
What is the best way to now return the phone instance, and LineFormSet back to the view for rendering in the template??
If I just return a context, my view gets only string "phoneline_set". But I want to do something like
$.post("addUserPhone/",phoneData,function(data){
$('.scroll').append("<h2> {{ line_set }} </h2>")
});
If I serialize using Json and pass how can I pass the LineFormSet and use it in template?
Currently if I try to serialize my client_lines formset I get the error
AttributeError: 'LineFormFormSet' object has no attribute '_meta'
Any help is appreciated, Thanks!!
Just elaborating on Daniel's answer as requested in the comment.
Django is an MVC style framework. Models are used in order to store and access data. In Django controllers are called views, which have a job of getting a request from a user with a certain URL, get some data which might be associated with the url, and then push that data throught some tempalte which will use the data view gave it in order to fill in the placeholders inside of the template.
Here is a simple example which explains all the aspects. Imagine that there is a web site which has a database of books. So your model would store information relevant to each book - Title, Author, ISBN number, etc.
# models.py
class Book(models.Model):
title = models.CharField(max_length=64)
author = models.CharField(max_length=64)
isbn = models.CharField(max_length=64)
Now you want to add a URL example.com/book/<id>/ which will display all of the information about the book with specified id. For that to happen, couple of things need to happen. First Django controller has to catch the url with this pattern. You specify the url pattern in the urls.py file.
# urls.py
urlpattern('',
url(r'^book/(?P<id>\d+)/$', views.book),
)
Since urls.py specify a mapping between url patterns and views, that tells Django that whenever user goes to a URL with the specified pattern, Django has to give the request to the view book which will know what to do. Additionally Django will pass the book id to the view.
# views.py
def book(request, id):
# get the book
book = get_object_or_404(Book, pk=id)
context = {
'book': book
}
return render_to_response('book_template.html', context)
So inside of the view, given the ID of the book, it uses models in order to look up the book from the database, and it case it is not found, it returns 404 error to the user. Then it populates a dictionary which I called context with some values which it will pass to the template. The job of the template is to take this context dictionary and use values inside of it in order to fill in some placeholders inside the template.
# book_template.html
<html>
<head>...</head>
<body>
<h1>{{ book.title }}</h1>
<p>Author: {{ book.author }}</p>
<p>ISBN: {{ book.isbn }}</p>
</body>
</html>
So the template will take the context from the view and then use the book inside of the context in order to fill in the values inside {{ }}.
In your case you are trying to return a context to the user which does not make much sense. What you have to do is create a template which will take the that context { 'phone': instance, 'line_set': client_lines } and according to it, will render some HTML which will be returned to the user. And that HTML you can pull using AJAX and then use it however you need it.
Hopefully this clarifies some concepts for you.
Django documentation is excellent so I would recomment to also read the intro. It will explain all of the syntax and some of the shortcuts I have used in this answer (render_to_response, etc).
You don't send the context as the Ajax response, you send a rendered template fragment using that context. The template should just be the HTML containing the form that you want to insert into your div.

Django: Redirect to current article after comment post

I am trying to use comments application in my project.
I tried to use code ({% render_comment_form for event %}), shown in the documentation here:
Django comments
And the question is how to make the form redirect to the same page, after the submission.
Also the big question is:
Currently if we have any error found in the for, then we're redirected to preview template.
Is that possible to avoid this behaviour and display errors over the same form (on the same page)?
I will show you how I resolved it in my blog, so you could do something similar. My comments are for Entry model in entries application.
First add new method for your Entry (like) object.
def get_absolute_url(self):
return "/%i/%i/%i/entry/%i/%s/" % (self.date.year, self.date.month, self.date.day, self.id, self.slug)
It generates url for entry objects. URL example: /2009/12/12/entry/1/lorem-ipsum/
To urls.py add 1 line:
(r'^comments/posted/$', 'smenteks_blog.entries.views.comment_posted'),
So now you should have at least 2 lines for comments in your urls.py file.
(r'^comments/posted/$', 'smenteks_blog.entries.views.comment_posted'),
(r'^comments/', include('django.contrib.comments.urls')),
For entries (like) application in views.py file add function:
from django.contrib.comments import Comment #A
...
def comment_posted(request):
if request.GET['c']:
comment_id = request.GET['c'] #B
comment = Comment.objects.get( pk=comment_id )
entry = Entry.objects.get(id=comment.object_pk) #C
if entry:
return HttpResponseRedirect( entry.get_absolute_url() ) #D
return HttpResponseRedirect( "/" )
A) Import on top of file to have
access for comment object,
B) Get
comment_id form REQUEST,
C) Fetch
entry object,
D) Use
get_absolute_url method to make
proper redirect.
Now:
Post button in comment form on entry site redirects user on the same (entry) site.
Post button on preview site redirects user on the proper (entry) site.
Preview button in comment form on entry site and on preview site redirects user on preview site
Thankyou page is not more in use (That page was quite annoying in my opinion).
Next thing good to do is to override preview.html template:
Go to django framework dir, under linux it could by /usr/share/pyshared/.
Get original preview.html template from DJANGO_DIR/contrib/comments/templates/comments/preview.html
Copy it to templates direcotry in your project PROJECT_DIR/templates/comments/entries_preview.html
From now on, it shoud override default template, You can change extends in this way: {% extends "your_pagelayout.html" %} to have your layout and all css files working.
Take a look at "Django-1.4/django/contrib/comments/templates/comments/" folder and you will see in the "form.html" file, there is the line
{% if next %}<div><input type="hidden" name="next" value="{{ next }}" /></div>{% endif %}
Therefore, in the Article-Detail view, you can include the "next" attribute in the context data, and then the comment framework will do the rest
class ArticleDetailView(DetailView):
model = Article
context_object_name = 'article'
def get_context_data(self, **kwargs):
context = super(ArticleDetailView, self).get_context_data(**kwargs)
context['next'] = reverse('blogs.views.article_detail_view',
kwargs={'pk':self.kwargs['pk'], 'slug': self.kwargs['slug']})
return context
Simplify Django’s Free Comments Redirection
Update: Now have the option to redirect as part of the comment form: see https://django-contrib-comments.readthedocs.io/en/latest/quickstart.html#redirecting-after-the-comment-post
This is a really simple redirect to implement. It redirects you back to the page where the comment was made.
When a comment is posted, the url comments/posted/ calls the view comment_posted which then redirects back to the referer page.
Be sure to replace [app_name] with your application name.
views.py
from urlparse import urlsplit
def comment_posted( request ):
referer = request.META.get('HTTP_REFERER', None)
if referer is None:
pass
try:
redirect_to = urlsplit(referer, 'http', False)[2]
except IndexError:
pass
return HttpResponseRedirect(redirect_to)
urls.py
( r'^comments/posted/$', '[app_name].views.comment_posted' ),