In django, how to use another model data from function based views - django

So I have a form that updates a key_instance object with a borrower. Currently my app needs the user to enter the name of the borrower, but I want it to display a dropdown list of data from another model the user model to select from, is there anyway to do this in a class based view? Here are my views.py and my template. What I was thinking is that I would like to use a get_list_or_404 on the user model and display it as a drop down list in the template and use that selection to populate the form field.
I manged to get the dropdown list to display in my template but I'm not sure as to how to save that value in my views.
Does anyone know if this is the right way or if this is doable? Thank you!!
views.py
def submit_key_request(request, pk):
"""
View function for renewing a specific keyInstance by admin
"""
key_inst=get_object_or_404(KeyInstance, pk=pk)
names = get_list_or_404(Users)
# If this is a POST request then process the Form data
if request.method == 'POST':
# Create a form instance and populate it with data from the request (binding):
form = UpdateKeyForm(request.POST)
# Check if the form is valid:
if form.is_valid():
# process the data in form.cleaned_data as required (here we just write it to the model due_back field)
key_inst.is_requested = True
key_inst.status = 'r'
key_inst.date_requested = datetime.date.today()
key_inst.borrower = form.cleaned_data['borrower']
key_inst.save()
# redirect to a new URL:
return HttpResponseRedirect(reverse('all-available-keys') )
# If this is a GET (or any other method) create the default form.
else:
form = UpdateKeyForm(initial={'borrower': 'N/A'})
return render(request, 'catalog/keyinstance_request_update.html', {'form': form, 'keyinst':key_inst})
template
{% extends "base_generic.html" %}
{% block content %}
<div class="wrapper">
<div class="centered"> <h1>Request Keys For Room: {{keyinst.roomkey}}</h1></div>
<div class="square-box">
<div class="square-content">
<form action="" method="post" >
{% csrf_token %}
<table style="display: inline-flex">
{{ form}}
</table>
<select name = 'name'>
{% for name in names %}
<option value="{{ name }}">{{ name }}</option>
{% endfor %}
</select>
<p>
(Please use their login name i.e. <b>{{ user.get_username }}</b>)
</p>
<p><input required id="checkBox" type="checkbox" onclick="validate()"> I accept the terms and conditions</p>
<p id="text" style="display:none">You Have Agreed To the Terms and Conditions</p>
<input type="submit" value="Submit" />
</form>
</div>
</div>
</div>
{% endblock %}

Here is how I manged to do it, Not sure if this is the best 'pythonic' or best practice. Please let me know if it's not.
my views.py
def submit_key_request(request, pk):
"""
View function for renewing a specific keyInstance by admin
"""
key_inst=get_object_or_404(KeyInstance, pk=pk)
names = get_list_or_404(User)
# If this is a POST request then process the Form data
if request.method == 'POST':
name = request.POST['name']
key_inst.is_requested = True
key_inst.status = 'r'
key_inst.date_requested = datetime.date.today()
key_inst.borrower = name
key_inst.save()
return HttpResponseRedirect(reverse('all-available-keys') )
# If this is a GET (or any other method) create the default form.
else:
pass
return render(request, 'catalog/keyinstance_request_update.html', {'keyinst':key_inst, 'names':names})
template
{% extends "base_generic.html" %}
{% block content %}
<div class="wrapper">
<div class="centered"> <h1>Request Keys For Room: {{keyinst.roomkey}}</h1></div>
<div class="square-box">
<div class="square-content">
<form action="" method="post" >
{% csrf_token %}
</br>
<select name = 'name' required>
{% for key in names %}
<option value="{{ key }}">{{ key }}</option>
{% endfor %}
</select>
<p>
(Please use their login name i.e. <b>{{ user.get_username }}</b>)
</p>
<p><input required id="checkBox" type="checkbox" onclick="validate()"> I accept the terms and conditions</p>
<p id="text" style="display:none">You Have Agreed To the Terms and Conditions</p>
<input type="submit" value="Submit" />
</form>
</div>
</div>
</div>
{% endblock %}

Related

How to save checkbox value in django?

I am using checkboxes in Html and everytime I refresh my page, the checkboxes are unchecked again. How do I prevent this from happening ? Do I have to use JS ?
I tought about booleans fields but I don't really know how to implement them ...
I looked at other threads and it talked about javascript, but I do not understand anything at all about it, nor how to implement it.
Here is my code :
views.py :
'
#login_required(login_url='/login')
def home(request):
check=False
MyToDo = Todo.objects.filter(user=request.user)
formtoDo = forms.TodoForm()
if request.method == 'POST' and 'todosub' in request.POST:
formtoDo = forms.TodoForm(request.POST)
if formtoDo.is_valid():
todoit = formtoDo.save(commit=False)
todoit.user = request.user
todoit.save()
return HttpResponseRedirect('/home?')
[...]
data ={'form': form, 'formtoDo': formtoDo, 'MyToDo': MyToDo, 'check':check}
return render(request, "capygenda/entries.html", data)
'
html :
<form method="POST", class="Entry">
{% csrf_token %}
<p>{{ formtoDo|crispy}} <button type="submit" name="todosub" >Add</button></p>
</form>
{% csrf_token %}
{% for toto in MyToDo %}
<form method="POST">
{% csrf_token %}
<ul class="list">
<li class="list-item">
<input type="checkbox" class="hidden-box" id="{{ toto.id }}" autocomplete="off"/>
<label for="{{ toto.id }}" class="check--label">
<span class="check--label-box"></span>
<span class="check--label-text">{{ toto }}</span>
</label>
<button class="button-24" role="button">Delete</button>
</ul>
</form>
Two steps:
In your views, if the form is submitted i.e., when request.method == 'POST' is True, pass another parameter {'checked: 'checked'}:
if request.method == 'POST' and 'todosub' in request.POST:
formtoDo = forms.TodoForm(request.POST)
if formtoDo.is_valid():
todoit = formtoDo.save(commit=False)
todoit.user = request.user
todoit.save()
return HttpResponseRedirect('/home?')
[...]
# ---- here look at the last item ----
data ={'form': form, 'formtoDo': formtoDo, 'MyToDo': MyToDo, 'check':check, 'checked':'checked'}
return render(request, "capygenda/entries.html", data
In your template, place that variable as an attribute in the input HTML element:
<input type="checkbox" class="hidden-box" id="{{ toto.id }}" autocomplete="off" {{ checked }}/>
This way, the checked attribute of the input will be dynamically placed. If it was passed via POST method, you have it. Otherwise, it's just empty.
add checked in the input field if you want it to keep it pre-checked or dependent on View values.
<input {% if checked %} checked{% endif %}"/>

Django: How to add comments under post

I have trouble adding comments under my posts on the website I'm creating using Django.
This is my story.html file, which is supposed to show the story title, the story itself, all the comments of the story and give users the ability to add a new comment. Although the form is shown, it is not usable. Even though I have added comments to the stories manually through admin, none of them is shown.
{% extends "pinkrubies/base.html" %}
{% block content %}
<div class="post-preview">
<h2 class="post-title"> {{ story.title }}</h2>
<p class="post-subtitle">
{{ story.story }}
</p>
</div>
<div class="post-preview">
{% for com in latest_comments %}
<div class="post-preview">
<p class="post-subtitle"> {{ comment.com }} </p>
</div>
{% endfor %}
</div>
{% if user_id %}
<div class="post-preview">
<form action="{% url 'pinkrubies:story' user.id story.id %}" method="post">
{% csrf_token %}
<div class="form-group">
<p class="post-title">
Comments
</p>
<textarea id="text" name="text"class="form-control" placeholder="Comment" rows="4">{{ comment.com }}
</textarea>
</div>
<button type="submit" class="btn btn-primary"> Submit </button>
</form>
</div>
{% else %}
<p class="post-meta">You must have an account to comment. Log in or Register</p>
{% endif %}
{% endblock %}
views.py
def story_view(request, user_id, story_id):
latest_comments = Comment.objects.order_by('-date')
if story_id is not None:
story = get_object_or_404(Story, pk=story_id)
else:
story = Story()
story.user_id = user_id
if request.method == 'POST':
story.title = request.post.get('title')
story.story = request.post.get('story')
story.date = timezone.now()
story.save()
return HttpResponseRedirect(reverse('pinkrubies:story', args=(user_id,)))
else:
context = {
'user_id': user_id,
'story_id': story_id,
'title': story.title,
'story': story,
'comments': story.comments,
'latest_comments': latest_comments
}
return render(request, 'pinkrubies/story.html', context)
def comment_view(request, comment, user_id):
latest_comments = Comment.objects.order_by('-date')
if request.method == 'POST':
comment.com = request.POST['com']
comment.date = timezone.now()
comment.save()
return HttpResponseRedirect(reverse('pinkrubies:story', args=(user_id,)))
else:
context = {'latest_comments': latest_comments}
return render(request, 'pinkrubies/story.html', context)
I am aware I have added the "latest_comments" in both views, I did that to see if any of it works and it doesn't. I'm not even sure that the comment_view is needed.
Also, when I try to submit a comment, this error is thrown:
AttributeError: 'WSGIRequest' object has no attribute 'post'
in story_view story.title = request.post.get('title')
Any help is welcome!
Thank you !!!
First of all, if you want to get something from POST, you should use request.POST.get('title'); although I would rather use a Form and let it handle the request.
At a first glance, this:
{% for com in latest_comments %}
<div class="post-preview">
<p class="post-subtitle"> {{ comment.com }} </p>
</div>
{% endfor %}
Sould be
{% for comment in latest_comments %}
<div class="post-preview">
<p class="post-subtitle"> {{ comment.com }} </p>
</div>
{% endfor %}
In your code, you're using com to iterate through latest_comments, yet you try to use comment to access com attribute (not sure how your Comment model looks like though)
It's accessed via request.POST. WSGIRequest object does not have a post field it has POST field.
Also, you are not sending the fields you are attempting to read from request.
...
story.title = request.POST.get('title')
story.story = request.POST.get('story')
...
only field you are sending is called text and it should be accessed like this
text = request.POST.get('text')
also template has more errors please check your code once again.

django 2.0 work with forms without jquery

from django import forms
class Find(forms.Form):
object_name = forms.CharField()
views.py
def get_obj(request, object_name='000'):
print(object_name)
form = FindSSK()
print(request.GET)
urlpatterns = [
# path(r'ssk/<str:object_name>/', get_obj),
re_path(r'^(?P<object_name>)#$', get_obj),
path(r'', get_obj),
]
{% block find %}
<form class="form-inline ml-5" action="#" method="GET">
{% comment %} {{form}} {% endcomment %}
{% comment %} <input type="number" class="form-control" placeholder="Enter obj" aria-label="Search"> {% endcomment %}
{% comment %} <input type="text" > {% endcomment %}
<input type="text" name="object_name" />
<input class="btn btn-outline-success ml-1 fas fa-search" type="submit" >
</input>
</form>
{% endblock %}
When i push to submit on forms, he will redirect http://127.0.0.1:8000/?object_name=001
But var object_name steal 000
result print in get_obj()
000
<QueryDict: {'object_name': ['001']}>
Sorry for bad English.
You're not able to get the argument needed because you're actually sending the value as a GET argument. However object_name is passed in your view as an argument and as URL parameter for your URL pattern, means that this should be included in the URL like url/object_name/ == http://127.0.0.1:8000/001/. Not sure this is what fits better your need.
To send data to the view, you could use a POST request or a GET request as you did with http://127.0.0.1:8000/?object_name=001.
For both options above, you don't need to have object_name as a parameter neither this ^(?P<object_name>) in url pattern.
VIEW: def get_obj(request object_name='000'):
______________________
URL: re_path(r'^$', get_obj),
method="GET": If you use GET request in form <form class="form-inline ml-5" action="#" method="GET"> you could retrieve the value like the following
def get_obj(request):
object_name = request.GET.get('object_name') # object_name is the field name in form
print(object_name)
method="POST": If you use POST request in form <form class="form-inline ml-5" action="#" method="POST"> you could retrieve the value like the following
def get_obj(request):
object_name = None
if request.method == 'POST':
object_name = request.POST.get('object_name')
print(object_name)
If you use POST request, don't forget to add {% csrf_token %} in your form

In flask,how to query data use a selectfield as condition and display with pagination

I want to query data,use the selectfield as a condition,then show the result in a html and use paginage.
my question is when i display my data,the first can display normally but when i click the next_page,the selectfield is none and the data can not display.
what should I do to keep the selectfield when I click the next_page?
Your view should accept an integer to allow for the passing of the current datum. Below is an example:
#app.route('/view/<int:page>',methods=['GET'])
def view(page=1):
if request.method == 'POST':
select = int(request.form.get('select'))
print(select)
per_page = 2
try:
users = User.query.order_by(User.email.asc()).paginate(select,
per_page=per_page,
error_out=False)
except NameError:
users = User.query.order_by(User.email.asc()).paginate(page,
per_page=per_page,
error_out=False)
return render_template('view.html',users=users)
The view would look something like this:
<html>
<head>Welcome</head>
<body>
<form method="POST" action="{{ url_for('view', page=users.prev_num + 1) }}">
<div>
<div>
<span>Please select</span>
<select name="select">
{% for user in users.items %}
<option value="{{ user.id }}">{{ user.username }}</option>
{% endfor %}
</select>
</div>
<button type="submit">Go</button>
</div>
</form>
{% if users.has_prev %}<< Newer users{% else %}<< Newer posts{% endif %} |
{% if users.has_next %}Older users >>{% else %}Older posts >>{% endif %}
</body>
</html>

Django identifying non field validation error is associated with which form

Is there a way to identifying the validation error is associated with which form for a template contaning multiple forms?
Let me explain the scenario. I have login window popup script within my base.html
<div id="dialog1" class="window">
<form method="post" action="/accounts/login/?next=/IW/home" id='login-form' name=login-form>{% csrf_token %}
<div class="d-header">
{{ form.non_field_errors }}
<input type="text" name="username" id="id_username" value="" onclick="this.value=''"/><br/>
<input type="password" name="password" id="id_password" value="" onclick="this.value=''"/><br/>
<input type="hidden" name="login_form" value="1" />
<input type="submit" value="login" />
</div>
{% endif %}
</div>
</form>
</div>
<div id="mask"></div>
{% if form.non_field_errors %}
<script>
var maskHeight = $(document).height();
var maskWidth = $(window).width();
//Set heigth and width to mask to fill up the whole screen
$('#mask').css({'width':maskWidth,'height':maskHeight});
$('#mask').show();$('.window').show();
</script>
{% endif %}
As all other templates extends base,html whenever there is an error non_field error then login window pops up . I would like to show the login error only when login form is submit not on submit of someother form with a non field error.
For this I need to identify the name of the form.something like this {% ifequal form.form_name login_form %} - Display login error .Is this possible??
They isn't anything special about the name 'form' in the template. It's just a default context name, you can choose to name your forms anything you like.
Just name the forms differently in your context:
from django.http import Http404
def detail(request, poll_id):
# NOTE: This view code isn't really form processing code, just using it to show
# how you can pass different names into your template context.
login_form = MyLoginForm()
detail_form = MyDetailForm()
try:
p = Poll.objects.get(pk=poll_id)
except Poll.DoesNotExist:
raise Http404
return render_to_response('polls/detail.html', {'poll': p, 'login_form': login_form, 'detail_form': detail_form})
And then:
<div id="dialog1" class="window">
<form method="post" action="/accounts/login/?next=/IW/home" id='login-form' name=login-form>
{% csrf_token %}
<div class="d-header">
{{ login_form.non_field_errors }}
.
.
.
Also, if you want to do multiple instances of the same form type, have a look at formsets