ListView in Django Assistance - django

OK, so I have just done a rather extensive Django tutorial online and wanted to dive into my first project to see how I would go.
I started off alright and then hit a pretty big road block that I am trying to overcome with no luck, so if you guys could help I will be forever in your debt!
So the project itself is simply making a website for a few of my mates where we can login and view some stats on bets we have with each other.
What I have done so far:
I created two models in models.py with the following code:
from django.db import models
# Create your models here.
class Team(models.Model):
team_name = models.CharField(max_length=500, unique=True)
wins = models.PositiveIntegerField()
losses = models.PositiveIntegerField()
class Predictions(models.Model):
combined_teams = models.CharField(max_length=800)
player_name = models.CharField(max_length=200, primary_key=True)
predicted_wins = models.PositiveIntegerField()
def __str__ (self):
return self.player_name
I created a login screen, this is the first screen the user will come to (not relevant for the question)
I created a static folder with some css styling for a couple of the pages and made some minor changes to the settings files.
I then went on to setup my views.py file and a couple of urls.py files too, as follows:
###VIEWS.PY####
from django.shortcuts import render
from django.views.generic import TemplateView, ListView
from django.contrib.auth.mixins import LoginRequiredMixin
from .models import Predictions, Team
class WelcomeView(LoginRequiredMixin,TemplateView):
template_name = 'merchbet/welcome.html'
class HomeView(LoginRequiredMixin, TemplateView):
template_name = 'merchbet/home.html'
class PredictionListView(LoginRequiredMixin, ListView):
model = Predictions
def get_queryset(self):
return Predictions.objects.order_by('-player_name')
class GalleryView(LoginRequiredMixin,TemplateView):
template_name = 'merchbet/gallery.html'
URLS.PY
from django.contrib import admin
from django.urls import path,include
from django.contrib.auth.urls import views
urlpatterns = [
path('', views.LoginView.as_view(), name='login'),
path('account/profile/', include('merchbet.urls')),
path('admin/', admin.site.urls),
]
URLS.PY### IN MY APP FOLDER
from django.urls import path
from . import views
app_name = 'merchbet'
urlpatterns = [
path('', views.WelcomeView.as_view(), name='welcome'),
path('home/', views.HomeView.as_view(), name='home'),
path('predictions/', views.PredictionListView.as_view(), name='prediction_list'),
path('gallery/', views.GalleryView.as_view(), name='gallery')
I then executed the following script, so that I could load up my friends "predictions" for our NBA bets this season with the following program:
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE','mysite.settings')
import django
django.setup()
from merchbet.models import Predictions, Team
predictions = ['Burger', 'Houston Rockets and Oklahoma City Thunder', 101,
'Buzz','Houston Rockets and Boston Celtics', 115, 'Kimon', 'Sacramento Kings and Atlanta Hawks', 44,
'Muller','Utah Jazz and Boston Celtics', 118, 'Barlow', 'Los Angeles Lakers and Milwaukee Bucks', 102,
'Larter','Golden State Warriors and Atlanta Hawks', 83, 'Hume', 'Los Andeles Lakers and Philadelphia 76ers',
104]
def add_predictions():
for index, entry in enumerate(predictions):
if index < len(predictions)-2:
if (type(predictions[index+2]) == type(1)):
player_name = predictions[index]
combined_teams = predictions[index+1]
predicted_wins = predictions[index+2]
preds = Predictions.objects.get_or_create(player_name=player_name,combined_teams=combined_teams,predicted_wins=predicted_wins)[0]
if __name__ == '__main__':
print("Populating the databases...Please Wait")
add_predictions()
print('Populating Complete')
The above worked fine and I can see in my Django Admin view of the site that there are 7 objects of the Predictions class all named after the "player_name" variable as it is the primary key:
So after all of this I am trying to simply use a for loop in an html document, that will help to print out the "player_name" and then I can show the "combined_teams" and "predicted_wins" but I just can not get it to work.
{% for prediction in prediction_list %}
<h1>{{ prediction.player_name }}</h1>
{% endfor %}
I have put a heap of effort into this post, so I am hoping some genius out there can lend a hand!
edit: I know the colour of the text is white, it is against a black background, so that isn't an issue :-)
Thanks!

You need to use object_list instead of prediction_list for merchbet/prediction_list.html, like this:
{% for prediction in object_list %}
<h1>{{ prediction.player_name }}</h1>
{% endfor %}
For more details, please check the documentation.

Related

How can I print the url to the order id field of my django form?

I am doing a simple form site with Django. This is what my sites url is looks like: mysite.com/register/12345678
I want to print the part after the register (12345678) to the order id field. When someone goes this mysite.com/register/87654321 url then i want to print it.
How can i do that? These are my codes.(Currently using Django 1.11.10)
forms.py
from django import forms
from .models import Customer
from . import views
class CustomerForm(forms.ModelForm):
class Meta:
model = Customer
fields = (
'order_id','full_name','company','email',
'phone_number','note')
widgets = {
'order_id': forms.TextInput(attrs={'class':'orderidcls'}),
'full_name': forms.TextInput(attrs={'class':'fullnamecls'}),
'company': forms.TextInput(attrs={'class':'companycls'}),
'email': forms.TextInput(attrs={'class':'emailcls'}),
'phone_number': forms.TextInput(attrs={'class':'pncls'}),
'note': forms.Textarea(attrs={'class':'notecls'}),
}
views.py
from django.shortcuts import render
from olvapp.models import Customer
from olvapp.forms import CustomerForm
from django.views.generic import CreateView,TemplateView
def guaform(request,pk):
form = CustomerForm()
if request.method == "POST":
form = CustomerForm(request.POST)
if form.is_valid():
form.save(commit=True)
else:
print('ERROR FORM INVALID')
theurl = request.get_full_path()
orderid = theurl[10:]
return render(request,'forms.py',{'form':form,'orderid':orderid})
customer_form.html
{% extends 'base.html' %}
{% block content %}
<h1>REGÄ°STRATÄ°ON</h1>
<form class="registclass" method="POST">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-default">REGISTER</button>
</form>
{% endblock %}
urls.py
from django.conf.urls import url
from django.contrib import admin
from olvapp import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^thanks/$',views.ThankView.as_view(),name='thank'),
url(r'^register/(?P<pk>\d+)',views.guaform,name='custform'),
]
You have passed the value to your view as 'pk' so you can use that to set the the initial value:
views.py
form = CustomerForm(initial={'order_id': pk})
SamSparx is right, here's some additional information to help prevent such errors in advance:
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^thanks/$',views.ThankView.as_view(),name='thank'),
url(r'^register/(?P<pk>\d+)',views.guaform,name='custform'),
]
You are using regex to parse your path. Regex is generally speaking not recommended in this case according to the docs because it might introduce more errors and is harder to debug. (Unoptimized) RegEx also tends to be slower.
For simple use cases such as your path here, consider choosing the default pathing syntax as below:
urlpatterns = [
url('admin/', admin.site.urls),
url('thanks/',views.ThankView.as_view(),name='thank'),
url('register/<int:pk>',views.guaform,name='custform'),
]
You could of course also use string instead of int depending on your usage of pk.
Your paths do not all end with a slash consistently. This might impact your SEO and confuse users. See this and this.
Also your form is not imported .as_view() for some reason which could cause some problems.

Beginner Django / Python / Postgres dev struggling with no model data output to html file

I have been working through some basic online Youtube tutorials for Django, which have been great, but I've been struggling the last few days with my Test-table app, being unable to display table data on my example Postgresql table placed on my index.html file. When I created the Postgres model (local hosted), it appears correctly with data in the admin page, and my index page loads successfully from my url and view file configurations, but is missing the table data specifically and I'm hoping for some guidance on what I am doing incorrectly. I understand there are more dynamic configurations for the URL and views, but I was attempting to get a basic one working first...
models.py file:
from django.db import models
class products(models.Model):
Phone = models.TextField(primary_key=True)
Version = models.TextField(max_length=100)
Price = models.FloatField()
Sales = models.IntegerField()
class Meta:
db_table = "productlist"
Url file:
from django.contrib import admin
from django.urls import path
from . import views
app_name = 'Test_table'
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.sales),
]
views.py
from django.shortcuts import render
from Test_table.models import products
# from django.http import HttpResponse
def sales(request):
ph_data = products.objects.all(),
return render(request, 'Test_table/index.html', {'ph_data': ph_data})
html file:
<table border='3'>
<tr>
<th>Phone</th>
<th>Version</th>
<th>Price</th>
<th>Sales</th>
</tr>
{% for i in ph_data %}
<tr>
<td><h3>{{i.Phone}}</h3></td>
<td><h3>{{i.Version}}</h3></td>
<td><h3>{{i.Price}}</h3></td>
<td><h3>{{i.Sales}}</h3></td>
</tr>
{% endfor %}
</table>
Just remove , from ph_data = products.objects.all(), , rest is fine
Correct code :
from django.shortcuts import render
from Test_table.models import products
# from django.http import HttpResponse
def sales(request):
ph_data = products.objects.all()
return render(request, 'Test_table/index.html', {'ph_data': ph_data})
And make sure to add data from admin to products table to view it.

Pulling data from db causing 404 page not found error

I'm trying to filter my views in such a way that when a specific school is chosen, pk of the school will be placed in a view function called major which would further query the db to display the proper majors corresponding to that school.
I now get a page not found 404 error, and can't figure out why.
url.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
path('<int:Major>/', views.Major, name='Major')
]
models.py
from django.db import models
class Major(models.Model):
name = models.CharField(max_length=30, db_index=True)
class School(models.Model):
name = models.CharField(max_length=50, db_index=True)
school_Major_merge = models.ManyToManyField(Major, through='School_Major')
class School_Major(models.Model):
major = models.ForeignKey(Major, on_delete=models.CASCADE)
school = models.ForeignKey(School, on_delete=models.CASCADE)
class professor(models.Model):
ProfessorIDS = models.IntegerField()
ProfessorName = models.CharField(max_length=100)
ProfessorRating = models.DecimalField(decimal_places=2,max_digits=4)
NumberofRatings = models.CharField(max_length=50)
#delete major from the model
school = models.ForeignKey(School , on_delete=models.CASCADE)
major = models.ForeignKey(Major , on_delete=models.CASCADE)
def __str__(self):
return self.ProfessorName
views.py
from django.http import HttpResponse
from django.shortcuts import render
from .models import professor, School, Major, School_Major
def index(request):
schools = School.objects.all()
return render(request, 'locate/index.html', {'schools': schools})
def Major(request, school_pk):
#Filter to a show the association of 1 schools majors
school_choice = Major_School.objects.filter(school_id = school_pk)
#Filter majors names required
majors = Major.objects.filter(id = school_choice.major_id)
return render(request, 'locate/major.html', {'majors' : majors})
I will post the code for the index file which pulls the schools info below, and when clicking on the school (hyperlink set) its basically suppose to pass the primary key of the school into the Major function which would then do further filtering.
<ul>
{% for list in schools %}
<li>{{list.name}}</li>
<br><br>
{%endfor%}
</ul>
The primary key for the school is pulled properly but for some reason the function doesn't fire up when I click on the hyperlink for the school I receive the 404 page not found error.
Purpose of the Major function,
1) Receive the Primary key of school, which will be passed to the M2M Table.
2) Now that ONLY majors corresponding to that school are displayed, Filter and store ONLY the majors which have the primary keys associated to the school chosen
I think the logic of my function is correct, I just can't understand again why i'm getting the 404 error.
Here is the exact error when I click the first school, which has a PK = 1
The current path, locate/{% url 'Major' 1/, didn't match any of these.
Update:
I went based on the suggestions below, and an example I had laying around that the format I have for the index.html is proper for the dispatcher, as well as the dispatcher is set properly aswell but WHY OH WHY does the {% still pop up I don't get it, I restarted the server thinking maybe it was bugging around but nada.
index.html
{% for list in schools %}
<li>{{list.name}}</li>
<br><br>
{%endfor%}
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
path('<int:school_pk>/', views.Major, name='Major')
]
The current path Error I'm having is still the same, but what I don't understand is after fixing the template to the proper format (I also used a example project I had as a reference that doesn't have this issue that passes a parameter) i'm not passing just the /locate/school_pk but the curly braces and the %
locate/ [name='index']
locate/ <int:school_pk>/ [name='Major'] <== This one
admin/
register/ [name='register']
profile/ [name='profile']
login/ [name='login']
logout/ [name='logout']
[name='blog-home']
about/ [name='blog-about']
post/<int:pk>/ [name='post-detail']
post/new/ [name='post-create']
post/<int:pk>/update/ [name='post-update']
post/<int:pk>/delete/ [name='post-delete']
user/<str:username> [name='user-posts']
^media/(?P<path>.*)$
The current path, locate/{% url 'Major' 1/, didn't match any of these.
Notice the {% is added in there, even after I fixed my mistake.
I think the template should be:
<li>{{list.name}}</li>
Where the URL is something like this:
path('<int:school_pk>/', views.Major, name='Major')
For reference please check the documentation.
In your for loop it should be
<ul>
{% for list in schools %}
<li>{{list.name}}</li>
<br><br>
{%endfor%}
</ul>
Just remove double curly braces {{ }}
So I noticed that there was a space between this specific url dispatcher in the error message
locate/ [name='index']
locate/ <int:school_pk>/ [name='Major'] <== This one
admin/
register/ [name='register']
profile/ [name='profile']
login/ [name='login']
logout/ [name='logout']
[name='blog-home']
about/ [name='blog-about']
post/<int:pk>/ [name='post-detail']
post/new/ [name='post-create']
post/<int:pk>/update/ [name='post-update']
post/<int:pk>/delete/ [name='post-delete']
user/<str:username> [name='user-posts']
^media/(?P<path>.*)$
The current path, locate/{% url 'Major' 1/, didn't match any of these.
So I added a space to the url.py which seemed to have done the trick
url.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
path(' <int:school_pk>/', views.Major, name='Major')
]
All my other urls in my main project are setup the same way but don't have this problem, but for some reason everything i tried it wouldn't nudge, I had to place a space in order for it to work

Django parler TranslatableSlugMixin translates from English to another language, but once translated cannot be translated back returns 404

I'm using Django CMS with Django Parler and have run into a problem that is driving me mad, so if anybody could help, it would be much appreciated!
So I'm creating a simple blog app that has the slug as a translatable field. Here is the model simplified:
from parler.models import TranslatableModel, TranslatedFields
class Article(TranslatableModel):
...
translations = TranslatedFields(
...
slug = models.SlugField(_('slug'), max_length=255, blank=True, allow_unicode=True),
meta = {'unique_together': (('language_code', 'slug'),)}
)
...
def get_absolute_url(self):
return reverse('blog:article_detail', kwargs={'slug': self.slug})
Here are the urls:
from django.conf.urls import include, url
from .views import ArticleDetailView
urlpatterns = [
...
url(r'^(?P<slug>\w[-\w]*)/$', ArticleDetailView.as_view(), name='article_detail'),
]
And finally here is the view:
from django.views.generic import DetailView
from parler.views import TranslatableSlugMixin
from .models import Article
class ArticleDetailView(TranslatableSlugMixin, DetailView):
model = Article
template_name = 'blog/_article.html'
I've created an article that is in English, French & German, with a different slug for each language, lets call those:
/en/blog/english-slug
/fr/blog/french-slug
/de/blog/german-slug
I can navigate to these all correctly, but in Django CMS you have the language menu at the top that on the English page shows the links as:
/en/blog/english-slug
/fr/blog/english-slug
/de/blog/english-slug
This is fine, as that's what the TranslatableSlugMixin in the view handles (see here http://django-parler.readthedocs.io/en/latest/api/parler.views.html).
So when I click one of the links (say the French one) the view correctly finds the correct article and redirects me to the correct url. So clicking:
/fr/blog/english-slug
Has taken me correctly to:
/fr/blog/french-slug
But here's where it's all going wrong. I now want to navigate back to the English page, which is showing as:
/en/blog/french-slug
But when I click the link it navigates to a 404. This is the same if I navigate to the German URL from the French one. However if I go from English to German straight away it works.
Sorry, I know this is confusing to explain but it seems the translation works one way from base/default to other language but doesn't work correctly when swapping between languages or back to the base/default.
Surely TranslatableSlugMixin is designed to allow this to happen?! So am I missing something here?
Any help would be much appreciated. Happy to provide more info if necessary.
Thanks
Ok so I've figured out how to make this work and it turns out it's a combination of things...
Using the default Django CMS chooser was a mistake:
{% language_chooser "menu/language_chooser.html" %}
This leads to the URLs I described above:
/en/blog/english-slug
/fr/blog/english-slug
/de/blog/english-slug
Reading the Django Parler docs led me to using their language navigation menu:
{% for lang_code, title in LANGUAGES %}
{% get_language_info for lang_code as lang %}
{% get_translated_url lang_code as tr_url %}
{% if tr_url %}<li{% if lang_code == LANGUAGE_CODE %} class="is-selected"{% endif %}>{{ lang.name_local|capfirst }}</li>{% endif %}
{% endfor %}
This leads to the urls pointing to the correct location:
/en/blog/english-slug
/fr/blog/french-slug
/de/blog/german-slug
For the Django Parler navigation to work I needed to update the get_absolute_url() in the model to handle different languages. I did that as follows:
from django.utils.translation import get_language
from parler.models import TranslatableModel, TranslatedFields
class Article(TranslatableModel):
...
def get_absolute_url(self):
language = get_language()
if self.has_translation(language):
slug = self.safe_translation_getter('slug', language_code=language)
return reverse('blog:article_detail', kwargs={'slug': slug})
# no translation so fallback to all article list
return reverse('blog:article_list')
Phew! That was a headache! Hopefully this helps somebody else in the future!
P.S. During my research I came across this blog app that seems really great:
https://github.com/nephila/djangocms-blog
It helped me get to the bottom of this nightmare!
UPDATE
Looking at the get_absolute_url() in djangocms-blog (link above), they have a far better solution to the problem. Their implementation is:
from django.utils.translation import get_language
from parler.models import TranslatableModel, TranslatedFields
class Article(TranslatableModel):
...
def get_absolute_url(self, lang=None):
if not lang or lang not in self.get_available_languages():
lang = self.get_current_language()
if not lang or lang not in self.get_available_languages():
lang = get_language()
with switch_language(self, lang):
slug = self.safe_translation_getter('slug', language_code=lang, any_language=True)
return reverse('blog:article_detail', kwargs={'slug': slug})
Thanks nephila, this has saved me from a lot of cursing and frustration :)

Uploaded images not showing, wrong path

I've got a problem with displaying images that were uploaded from admin panel. Django renders wrong path, probably due to my configuration mistake somewhere...
This is my model definition:
class Article(models.Model):
"""News article, displayed on homepage to attract users"""
class Meta:
db_table = 'article'
title = models.CharField(max_length=64)
headline = models.CharField(max_length=255)
content = HTMLField()
image = models.ImageField(upload_to = 'articles/', null=True, blank=True)
active = models.BooleanField()
created_at = models.DateTimeField()
def __unicode__(self):
return self.title
This is url configuration:
from django.conf.urls import patterns, include, url
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = patterns('',
# some stuff
) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
settings.py:
PROJECT_DIR = os.path.dirname(__file__)
MEDIA_ROOT = os.path.join(PROJECT_DIR, "media")
MEDIA_URL = '/media/'
the view:
def slider(request):
context = Context ({ 'articles': Article.objects.order_by('-created_at')[:5] })
return render(request, 'articles/slider.html', context)
and the template:
{% for article in articles %}
<img src="{{ article.image.url }}" alt="" />
I would expect django to render http://127.0.0.1:8000/media/articles/slide-02.jpg but now it renders http://127.0.0.1:8000/media/slide-02.jpg. I've defined the upload_to=articles/ in the model class. So why does the article.image.url attribute return a path without this significant directory?
edit: I've got something wrong with my model. It doesn't recognize the upload_to directory:
$ ./manage.py shell
Python 2.7.3 (default, Aug 1 2012, 05:14:39)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from articles.models import Article
>>> Article.objects.all()
[<Article: Blackened Recordings Launches>, <Article: The Rockin' Return of Deep Purple>, <Article: See Emily Day 20th April>, <Article: Celebration Day Premieres In Four Countries Announced>, <Article: Waging heavy innovation>, <Article: Rush to play festival D'Ete, Quebec City>]
>>> Article.objects.all().get(pk=1)
<Article: Blackened Recordings Launches>
>>> Article.objects.all().get(pk=1).image
<ImageFieldFile: slide-03.jpg>
>>> Article.objects.all().get(pk=1).image.path
u'/var/www/django/djninja/djninja/media/slide-03.jpg'
>>> Article.objects.all().get(pk=1).image.url
'/media/slide-03.jpg'
Again, it should be media/articles/slide-03.jpg instead of media/slide-03.jpg. So I guess all routing/template is ok, something's wrong with the model.
In views.py:
from django.shortcuts import render_to_response, RequestContext
def slider(request):
articles = Article.objects.order_by('-created_at')[:5]
return render_to_response('articles/slider.html', locals(), context_instance = RequestContext(request)
In slider.html:
{% for article in articles %}
<img src="{{ MEDIA_URL }}{{ article.image.url }}" alt="" />
{% endfor %}
In urls.py:
from django.conf import settings
urlpatterns += patterns('',
(r'^media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT}),
)
Try using the above given codes.
Above solution is perfectly ok. My problem was the improperly configured fixtures written in JSON and loaded into the database. I thought that in you pass articles directory as the upload_to kwarg, it'll be dynamically loaded. It's not. It is used only during saving the image and is ignored during loading the image from the database. Thus, if I had
"image":"slide.jpg"
I changed it to:
"image":"articles/slide.jpg"
And it worked. In fact, it worked all the time, but I miss a note on that in django official docs.
Did you try to use a upload method :
def upload_path(self, filename):
return 'media/articles/%s' % filename
class Article(models.Model):
...
image = models.ImageField(upload_to=upload_path, null=True, blank=True)
...