Django ListView inserting blank <li> after each element - python

I am new to Django and trying to grasp why or how to mitigate the extra <li> and have not found anything yet. Here is an image of what the output is doing.
EDIT: I have tried cleaning the string as suggested below and still no luck. This happens even when I ran through the Django Tutorial. I know I can use JS or JQuery to remove them, however being as basic as this is, and knowing there are ONLY 2 objects for the model, I would like to know why it inserts this additional
And here is a snippet of my template:
{% extends "base_templates/stations.html" %}
{% block station_content %}
<h2>Stations</h2>
<ul>
{% for station in object_list %}
{% if station.name.strip != "" %}
<li>{{ station.name }}<li>
{% endif %}
{% endfor %}
</ul>
{% endblock %}
EDIT: Here is my view for this template as well
from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.views import generic
from django.views.generic import ListView
from django.utils import timezone
from .models import Customer, CustomerContact, Station, SubcontractorContact
# Create your views here.
class CustomerView(ListView):
model = Customer
class StationView(ListView):
model = Station

If you just check it for being empty, it might not validate for white space. Trim the string before you check it for being empty as " " and "" are not equal
Try:
if(station.name.strip()!="")

Okay, THANK YOU so much everyone who contributed... HOWEVER if we take a look at that wonderful closing <li> we see well theres no /... So once again thank you everyone, have a wonderful day!

Related

How to display my python code in a table on Django webpage?

I have written some code in Python that reads in two strings, removes the punctuation and then compares the words in them within a matrix table which it prints to the console.
How do I convert the code to be utilised within the Django framework. I want to display a similar matrix on the web. I've already imported it into views. Please may someone point me in the right direction? I've been using django project and lynda to learn as I go along,
Edit:
Merci for the help guys. Managed to get it to display on a webpage. But it is printing it all out as a single string. How do I style it a bit better?
Think of passing your data to a "Django webpage" as just passing a dictionary of your values to a Django template from your Django view.
What is a Django template?
A Django template is the 'T' in Django's 'MTV' design pattern. In the conventional MVC design pattern (Model-View-Controller), the View is where you display things. In Django, Templates are where you display things. Oddly enough, the 'View' in Django is actually the Controller. This took me a while to wrap my head around.
Why do we use a dictionary-like context?
By mapping keys to values we achieve super-fast [O(1)/constant] lookup in the Django templates.
With all of this in mind, I'd advocate using 'TemplateView' generic view, doing your work in a utils file, importing utils into views, and then passing your data to the template via the context dictionary. So it would look something like this:
local_utils.py
import string
import pandas as pd
pd.set_option('display.max_columns', None)
def generate_out_matrix():
with open('./arrayattempts/samp.txt', 'r') as file1:
sampInput=file1.read().replace('\n', '')
#print(sampInput)
with open('./arrayattempts/ref.txt', 'r') as file2:
refInput=file2.read().replace('\n', '')
#print(refInput)
sampArray = [word.strip(string.punctuation) for word in sampInput.split()]
refArray = [word.strip(string.punctuation) for word in refInput.split()]
out=pd.DataFrame(index=refArray,columns=sampArray)
for i in range(0, out.shape[0]):
for word in sampArray:
out.ix[i,str(word)] = out.index[i].count(str(word))
return out.as_matrix()
views.py
from appname.local_utils import generate_out_matrix
class Detail(TemplateView):
template_name = 'appname/yourhtml.html'
# Will render on each call to URL for 'Detail'
def get_context_data(self):
out = generate_out_matrix()
context['out'] = out
return context
appname/templates/yourhtml.html
{% if out %}
{% for row in out_matrix %}
{% for o in row %}
{{ o }}
{% endfor %}
<br>
{% endfor %}
{% endif %}
urls.py
path('/your_path', views.Detail.as_view()),
https://docs.djangoproject.com/en/2.0/ref/templates/api/#rendering-a-context
To send your data to your template you should add your variable to context at your views
from django.http import Http404
from django.shortcuts import render
from polls.models import Poll
def detail(request, poll_id):
... // your logic
out // your variable
return render(request, 'yourhtml.html', {'out': out})
In html will be like that
{{ out }}
{% for o in out %}
{{ o }}
{% endfor %}
https://docs.djangoproject.com/en/2.0/topics/http/views/
You can style your table with some CSS or using ny lib struct to handle tables
You can follow this guide
display django-pandas dataframe in a django template

Django: Listing documents from a local folder

I've been trying to find a way to display my documents from a local folder on to a web page. I was wondering about this in two ways: one was to use django's ListView, but I am not using models in this case, so I am unsure if it would work. The other way I'm going with this is by through this list method that I've made, but I am having trouble getting the proper contents (title, date) on to the webpage. They show up in lists that I created, but wont translate to the webpage. Its just a blank page. Here's my code:
views.py
import os, string, markdown, datetime
from P1config.settings import STATICBLOG_COMPILE_DIRECTORY,STATICBLOG_POST_DIRECTORY,STATICBLOG_STORAGE
def doclist(request):
mdown = markdown.Markdown(extensions = ['meta','extra', 'codehilite', PyEmbedMarkdown()])
posts = []
for item in os.listdir(STATICBLOG_POST_DIRECTORY):
if item.endswith('.md'):
continue
try:
with open(os.path.join(STATICBLOG_POST_DIRECTORY, item)) as fhandle:
content = fhandle.read() # (opening and reading the ENTIRE '.md' document)
mdown.convert(content) # (converting file from '.md' to ".html")
post = { 'file_name' : item }
if 'title' in mdown.Meta and len(mdown.Meta['title'][0]) > 0:
post['title'] = mdown.Meta['title'][0]
else:
post['title'] = string.capwords(item.replace('-', ' '))
if 'date' in mdown.Meta:
post['date'] = mdown.Meta['date'][0]
post['date']= datetime.datetime.strptime(post['date'], "%Y-%m-%d")
posts.append(post)
except:
pass
from operator import itemgetter
posts = sorted(posts, key=itemgetter('date'))
posts.reverse()
return render(
request,
'list.html',
{'post' : posts}
)
list.html
{% extends 'base.html' %}
{% block content %}
{% if post %}
{% for i in post %}
<h2>{{post.title}}</h2>
<p class="meta">{{post.date}}</p>
{% endfor %}
{% endif %}
{% endblock %}
and my urls.py:
from django.conf.urls import include, url, patterns
urlpatterns = patterns('blog_static.views',
(r'^postlist/', 'list'),
)
I have two questions:
Can you figure out where I am going wrong in this code?
Are there any alternative ways that I may go about doing this? This may be an inefficient way of listing documents from a local folder, so I am open to other options as well.
Any sort of help would be appreciated. Thanks!
It sounds like you are already familiar with, and could execute this using ListView. You can use ListView without a model - as referenced in various parts of the documentation ("is not necessarily a queryset"):
https://docs.djangoproject.com/en/1.8/ref/class-based-views/mixins-multiple-object/#django.views.generic.list.MultipleObjectMixin.get_queryset
Get the list of items for this view. This must be an iterable and may be a queryset (in which queryset-specific behavior will be enabled).
Therefore you should be able to do the following:
class MyListView(generic.ListView):
template_name = 'foobar.html'
def get_queryset(self):
return [1, 2, 3]
What's wrong with your example... it's the fact you're referencing post in your inner for loop as opposed to the i that you defined as the actual post.
It's confusing because you rename the python posts variable to post in the template context, then iterate over it as i.
posts in your template context is just a list, and has no attributes, keys, etc., named post.title.
post is array of dict objects. So
{% extends 'base.html' %}
{% block content %}
{% if post %}
{% for i in post %}
<h2>{{i.title}}</h2>
<p class="meta">{{i.date}}</p>
{% endfor %}
{% endif %}
{% endblock %}

Django context not rendering

I've got a Django template in HTML. I would like to pass a variable to this template using a context. However, when I render the template Django fills the spaces that reference this variable with the string specified by the TEMPLATE_STRING_IF_INVALID setting (I tested this).
Here's the relevant URLconf:
from django.conf.urls import patterns, url
from users import views
urlpatterns = patterns('',
url(r'^$', views.users),
url(r'(?P<pk>\d+)/$', views.userdetail),
)
and here's the view it references:
from django.template import RequestContext, loader
...
def userdetail(request, pk):
user = get_object_or_404(User, pk=pk)
template = loader.get_template('users/userdetail.html')
context = RequestContext(request, {'user': user})
return HttpResponse(template.render(context))
I'm fairly certain it's due to a syntax error in specifying the context but after looking at it for an hour I can't find one. I'm happy to post additional code if you think it may be relevant. Can anyone spot my mistake?
Template for those interested:
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif%}
<h1> You are viewing the page for the individual user {{ user.name }} </h1>
This user has created the following posts:
{% for post in user.post_list %}
{{ post.title }}</li>
{% endfor %}
<p>
Created on {{ user.creation_date }}
</p>
The OP wrote:
My supervisor just came around and fixed it really quickly. The issue is that templates have some predefined keywords. User is one of these keywords so django was upset that I was passing it {'user':user} in the context. Changing to {'customuser':user} avoids the collision with the django keyword and fixes this issue.

How to use the built-in 'password_reset' view in Django?

I have set the following entry in the urls.py
(r'^password_reset/$', 'django.contrib.auth.views.password_reset'),
but once I go to http://127.0.0.1:8000/password_reset/ I get the error message:
NoReverseMatch at /password_reset/
Reverse for 'django.contrib.auth.views.password_reset_done' with arguments '()' and keyword arguments '{}' not found.
I was expecting password_reset_done view also to be coming out of the box. So what am I supposed to do at this stage?
UPDATE
After trying Blair's solution, I got a step closer.
(r'^password_reset_done/$', 'django.contrib.auth.views.password_reset_done'),
According to the book 'Django 1.0 Website Development', these built-in views should be used out of the box without further hassle. But maybe it has changed since Django 1.0...
Would be great if someone could shed light on this. Thanks
I have finally found the solution. I think there is always the slight misunderstanding between MVC and MTV pattern. In MTV (Django) the View stands for the controller and the Template stands for the View.
Hence while its true that the change password "Views" are coming built-in out-of-the-box, the actual templates (look & feel) still needs to be generated by the user while the underlying form (widget) is generated by Django automatically. It gets more clear when looking at the code.
Therefore add these two lines to url.py
(r'^change-password/$', 'django.contrib.auth.views.password_change'),
(r'^password-changed/$', 'django.contrib.auth.views.password_change_done'),
Then Under myproject/templates/registration add these two files
password_change_done.html
{% extends "base.html" %}
{% block title %}Password Change Successful{% endblock %}
{% block head %}Password Change Completed Successfully{% endblock %}
{% block content %}
Your password has been changed successfully. Please re-login with your new credentials
login or go back to the
main page.
{% endblock %}
password_change_form.html
{% extends "base.html" %}
{% block title %}Change Registration{% endblock %}
{% block head %}Change Registration{% endblock %}
{% block content %}
<form method="post" action=".">
{{form.as_p}}
<input type="submit" value="Change" />
{% csrf_token %}
</form>
{% endblock %}
Django needs to know which URL to redirect the user to once they have completed the form on the password_reset page. So add another line to your URL configuration:
(r'^password_reset_done/$', 'django.contrib.auth.views.password_reset_done'),
As of django 1.11 password_change view is deprecated.
Deprecated since version 1.11: The password_change function-based view should be replaced by the class-based PasswordChangeView.
What worked for me was:
In urls.py
from django.contrib.auth import views as auth_views
...
url('^account/change-password/$',
auth_views.PasswordChangeView.as_view(
template_name='registration/passwd_change_form.html'),
name='password_change'),
url(r'^account/password-change-done/$',
auth_views.PasswordChangeDoneView.as_view(
template_name='registration/passwd_change_done.html'),
name='password_change_done'),
And then add the couple of templates passwd_change_form.html and passwd_change_done.html under registration.
Note that I'm not using the default name, for some reason when I did that it defaulted to the django admin views.

Could not parse the remainder in template

This is my DjangoTemplates/(mysite)/index.html. I'm trying to do some math in my index.html. I want to display the sum of the entire Stakes.amount_won for each user_name in the for loop. I think I have the syntax correct for the math, but it does not seem to work in the template.
The for loop should go through each user_name, and display their user_name as a link with the Amount Won: (total of amount_won for that user_name) below.
from django.db.models import Sum
<h1> Players </h1>
{% if latest_player_list %}
<ul>
{% for player in latest_player_list %}
<li>{{ player.user_name }} <br>Total Won: {{Stakes.objects.filter(player__user_name).aggregate(Sum('amount_won'))}}
</li>
{% endfor %}
</ul>
<br>
{% else %}
<p>No players are available.</p>
{% endif %}
<h3>New Player</h3>
Sorry if this is noobish. Thank you in advance for the help!
Although the import statement is not part of the template language, this isn't actually your problem - it will just show as text. The actual problem is your function call: Django doesn't allow calls with parentheses in templates. Only functions with no parameters are allowed. You need to do the lookup in the view and pass it in the context.
Of course, this is all clearly explained in the documentation.
The quick answer here is that you're trying to do too much in the template - for example, you can't use a Python import statement in a template at all, so I imagine that's just rendering as text. What you'd generally want here is to do the query logic in your view class, then pass the data to the template for rendering.

Categories

Resources