I'm trying to learn Python Django with book "Example_Build_powerful_and_reliable_Python_web_applications" by Antonio Mele.
Really sorry for probably stupid questions, but i'm very new.
And sorry for my English, it isn't my native language.
Have some problem with one of the example from the book.
Do the same things as in the book, but URL's dont work.
MODELS.PY
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
from django.urls import reverse
class PublishedManager(models.Manager):
def get_queryset(self):
return super(PublishedManager, self).get_queryset().filter(status='published')
class Post(models.Model):
STATUS_CHOICES = (
('draft', 'draft'),
('published', 'published')
)
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=250,
unique_for_date='publish')
body = models.TextField()
publish = models.DateTimeField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
status = models.CharField(max_length=10,
choices=STATUS_CHOICES,
default='draft')
objects = models.Manager()
published = PublishedManager()
class Meta:
ordering = ('-publish',)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('blog:post_detail',
args=[self.publish.year,
self.publish.month,
self.day, self.slug])
VIEWS.PY
from django.shortcuts import render, get_object_or_404
from .models import Post
def post_list(request):
posts = Post.published.all
return render(request,
'blog/post/list.html',
{'posts': posts})
def post_detail(request, post):
post = get_object_or_404(Post, slug = post)
return render(request, 'blog/post/detail.html', {'post': post})
URLS.PY
from django.urls import path
from . import views
app_name ='blog'
urlpatterns = [
path('', views.post_list, name='post_list'),
path('<int:year>/<int:month>/<int:day>/<slug:post>/',
views.post_detail,
name='post_detail'),
]
BASE.HTML
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>{% block title %} {% endblock %}</title>
</head>
<body>
<div id="content">
{% block content %}
{% endblock %}
</div>
<div id="sidebar">
<h2>My Blog</h2>
<p>This is my blog</p>
</div>
</body>
</html>
LIST.HTML
{% extends "blog/base.html" %}
{% block title %}My blog{% endblock%}
{% block content %}
<h1>My Blog</h1>
{% for post in posts %}
<h2>
<a href="{{ post.get_absolute_url }}">
{{post.title}}
</a>
</h2>
<p class="date">
Published {{ post.publish }} by {{ post.author }}
</p>
{{ post.body|truncatewords:30|linebreaks }}
{% endfor %}
{% endblock %}
DETAIL.HTML
{% extends "blog/base.html" %}
{% block title %} {{ post.title }} {% endblock %}
{% block content %}
<h1> {{ post.title }} </h1>
<p class = "date">
Published {{ post.publish }} by {{ post.author }}
</p>
{{ post.body|linebreaks }}
{% endblock %}
Also add my urls to URLS here:
enter image description here
The problem is: when i click on posts on the page BASE.HTML i dont see correct URL and nothing is happening:
enter image description here
Really break my brain.
Thanks in advance for help.
Your VIEWS.py should contain the methods post(self,request) OR get(self,request) to be callable from the rendered HTML. The methods post_list(..) OR post_detail(..) are not callable on the Django framework.
Oh my f...ng god.
If somebody will face with the same problem..
In MODELS.PY just need to move Class Meta and 2 defs:
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
from django.urls import reverse
class PublishedManager(models.Manager):
def get_queryset(self):
return super(PublishedManager, self).get_queryset().filter(status='published')
class Post(models.Model):
STATUS_CHOICES = (
('draft', 'draft'),
('published', 'published')
)
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=250,
unique_for_date='publish')
body = models.TextField()
publish = models.DateTimeField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
status = models.CharField(max_length=10,
choices=STATUS_CHOICES,
default='draft')
objects = models.Manager()
published = PublishedManager()
class Meta:
ordering = ('-publish',)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('blog:post_detail',
args=[self.publish.year,
self.publish.month,
self.day, self.slug])
And then in will work good.
Very stupid mistake, so hard to find this..
Related
I used a form to create a django post with a single "text" field. Then I modified the post model. Now there are three forms "author", "body" and "title". Also changed the mentions in home.html and other files. Logically, it should work, but it gives an error in the file home.html
there is no such column: pages_posts.title
error in line 5
Some files from my project:
views.py
from django.contrib.auth.forms import UserCreationForm
from django.urls import reverse_lazy
from django.views.generic import TemplateView, CreateView, DetailView
from django.views.generic import ListView
from .models import Posts
class HomePageView(ListView):
model = Posts
template_name = 'home.html'
# post_list = Posts.title
# context_object_name = 'all_posts_list'
class AboutPageView(TemplateView):
template_name = 'about.html'
class SignUpView(CreateView):
form_class = UserCreationForm
success_url = reverse_lazy('login')
template_name = 'signup.html'
class NewPostUpView(CreateView):
form_class = UserCreationForm
success_url = reverse_lazy('login')
template_name = 'signup.html'
class BlogDetailView(DetailView):
model = Posts
template_name = 'post_detail.html'
class BlogCreateView(CreateView):
model = Posts
template_name = 'post_new.html'
fields = ['title', 'author', 'body']
models.py
from django.db import models
class Posts(models.Model):
title = models.CharField(max_length=200, default='False')
author = models.ForeignKey(
'auth.User',
on_delete=models.CASCADE,
)
body = models.TextField()
def __str__(self):
return self.title
class Meta:
verbose_name = 'Пост'
verbose_name_plural = 'Посты'
home.html
{% extends 'base.html' %}
{% block content %}
{% for post in object_list %}
<div class="post-entry">
<h2>{{ post.title }}</h2>
<p>{{ post.body }}</p>
</div>
{% endfor %}
{% endblock content %}
base.html
{% load static %}
<html>
<head>
<title>Django blog</title>
<link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400"
rel="stylesheet">
<link href="{% static 'css/base.css' %}" rel="stylesheet">
</head>
<body>
<div>
<header>
<div class="nav-left">
Home | About
</div>
</header>
{% if user.is_authenticated %}
<h3>Hi {{ user.username }}!</h3>
<p>Log out</p>
<div class="nav-right">
+ New Blog Post
</div>
{% else %}
<p>You are not logged in.</p>
Log In
{% endif %}
{% block content %}
{% endblock content %}
</div>
</body>
</html>
The title, body and author fields cannot be null. If you initially create these fields, there will be no error. But if we edit the post model, then we create fields for which there is no value in the pages table in this case. Then if we create new fields, we need to write a default value for each of them.
title = models.CharField(max_length=200, default='')
author =models.ForeignKey(
'auth.User',
default='',
on_delete=models.CASCADE, )
body = models.TextField(default='')
After these manipulations, do not forget to update the migrations
python manage.py makemigrations
python manage.py migrate
I created model Post and Comment, now I want to display comments from Post but I have a problem. In tutorial there is a line of code in html {% for comment in post.comments.all %} but isn't working in my app. If I set {% for comment in comments %} it works but displays all comments from models (I want only comments from the post). How to fix that? Below I pasted my code.
models.py
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=64, blank=False, null=False)
short_text = models.TextField(blank=False, null=False)
text = models.TextField(blank=False, null=False)
image = models.TextField(blank=False, null=False)
date = models.DateTimeField(auto_now_add=True, blank=True)
views = models.IntegerField(default=0)
class Comment(models.Model):
post = models.ForeignKey('main.Post', on_delete=models.CASCADE)
author = models.CharField(max_length=200)
text = models.TextField()
created_date = models.DateTimeField(auto_now_add=True, blank=True)
approved_comment = models.BooleanField(default=False)
def approve(self):
self.approved_comment = True
self.save()
def __str__(self):
return self.text
views.py
from django.shortcuts import get_object_or_404, render, redirect
from .models import Post, Comment
def index_pl(request):
posts = Post.objects.all()
return render(request, 'index_pl.html', {'posts': posts})
def single_article_pl(request, id):
posts = get_object_or_404(Post, pk=id)
posts.views = posts.views + 1
posts.save()
comments = Comment.objects.all()
return render(request, 'single_article_pl.html', {'posts': posts, 'comments': comments})
html
{% for comment in post.comments.all %}
<div class="comment">
<div class="date">{{ comment.created_date }}</div>
<strong>{{ comment.author }}</strong>
<p>{{ comment.text|linebreaks }}</p>
</div>
{% empty %}
<p>No comments here yet :(</p>
{% endfor %}
admin.py
from django.contrib import admin
from .models import Post, Comment
admin.site.register(Post)
admin.site.register(Comment)
In tutorial there is a line of code in html {% for comment in post.comments.all %} but isn't working in my app.
This is likely because they specified the related_name=… parameter [Django-doc] in the ForeignKey from Comment to Post, like:
# Option 1: set the related_name to 'comments'
class Comment(models.Model):
post = models.ForeignKey(
'main.Post',
related_name='comments',
on_delete=models.CASCADE
)
# …
The related_name=… specifies the name of the relation in reverse, so in this case accessing the Comments of a given Post object. By default this is model_name_set, so in this case comment_set.
You thus can either specify a related name; or you can acces the comment_set manager:
Option 2: use the default related_name
{% for comment in post.comment_set.all %}
<div class="comment">
<div class="date">{{ comment.created_date }}</div>
<strong>{{ comment.author }}</strong>
<p>{{ comment.text|linebreaks }}</p>
</div>
{% empty %}
<p>No comments here yet :(</p>
{% endfor %}
I am a beginner in Django. I am building a Django app, named PhoneReview. It will store reviews related to the latest mobile phone. It will also display phone brands, along with the associated phone models.
I have already created models, views and the template files. Now, I am facing a problem. I can't use slug in URLs. Right now, it looks like this:
Here are my codes of models.py located inside PhoneReview folder:
from django.db import models
from django.template.defaultfilters import slugify
# Create your models here.
class Brand(models.Model):
brand_name = models.CharField(max_length=100)
origin = models.CharField(max_length=100)
manufacturing_since = models.CharField(max_length=100, null=True, blank=True)
slug = models.SlugField(max_length=150, null=True, blank=True)
def __str__(self):
return self.brand_name
def save(self, *args, **kwargs):
self.slug = slugify(self.brand_name)
super().save(*args, **kwargs)
class PhoneModel(models.Model):
brand = models.ForeignKey(Brand, on_delete=models.CASCADE)
model_name = models.CharField(max_length=100)
launch_date = models.CharField(max_length=100)
platform = models.CharField(max_length=100)
slug = models.SlugField(max_length=150, null=True, blank=True)
def __str__(self):
return self.model_name
def save(self, *args, **kwargs):
self.slug = slugify(self.model_name)
super().save(*args, **kwargs)
class Review(models.Model):
phone_model = models.ManyToManyField(PhoneModel, related_name='reviews')
review_article = models.TextField()
date_published = models.DateField(auto_now=True)
# slug = models.SlugField(max_length=150, null=True, blank=True)
link = models.TextField(max_length=150, null=True, blank=True)
def __str__(self):
return self.review_article
Here are my codes of urls.py located inside PhoneReview folder:
from . import views
from django.urls import path
urlpatterns = [
path('index', views.BrandListView.as_view(), name='brandlist'),
path('phonemodel/<int:pk>/', views.ModelView.as_view(), name='modellist'),
path('details/<int:pk>/', views.ReviewView.as_view(), name='details'),
]
Here are my codes of views.py located inside PhoneReview folder:
from django.views import generic
from .models import Brand, PhoneModel, Review
class BrandListView(generic.ListView):
template_name = 'PhoneReview/index.html'
context_object_name = 'all_brands'
def get_queryset(self):
return Brand.objects.all()
class ModelView(generic.DetailView):
model = PhoneModel
template_name = 'PhoneReview/phonemodel.html'
class ReviewView(generic.DetailView):
model = Review
template_name = 'PhoneReview/details.html'
Here are my codes of apps.py located inside PhoneReview folder:
from django.apps import AppConfig
class PhonereviewConfig(AppConfig):
name = 'PhoneReview'
Here are my codes of index.html located inside templates folder:
{% extends 'PhoneReview/base.html' %}
{% load static %}
{% block title%}
Brand List
{% endblock %}
{% block content %}
<!--Page content-->
<h1>This is Brand List Page</h1>
<h2>Here is the list of the brands</h2>
<ul>
{% for brand in all_brands %}
<!-- <li>{{ brand.brand_name }}</li>-->
<li>{{ brand.brand_name }}</li>
{% endfor %}
</ul>
<img src="{% static "images/brandlist.jpg" %}" alt="Super Mario Odyssey" /> <!-- New line -->
{% endblock %}
Here are my codes of phonemodel.html located inside templates folder:
{% extends 'PhoneReview/base.html' %}
{% load static %}
{% block title%}
Phone Model Page
{% endblock %}
{% block content %}
<!--Page content-->
<h1>This is Phone Model Page</h1>
<h2>Here is the phone model</h2>
<ul>
<li>{{ phonemodel.model_name }}</li>
</ul>
<img src="{% static "images/brandlist.jpg" %}" alt="Super Mario Odyssey" /> <!-- New line -->
{% endblock %}
In index.html, I tried to replace <li>{{ phonemodel.model_name }}</li> with <li>{{ phonemodel.model_name }}</li>. But I get error.
How can I fix the issue?
Update: I added the codes provided by #arjun. However, I am getting an error. It says the following
OperationalError at /index
no such table: PhoneReview_brand
You need to pass slug instead of pk through your url if you want to use slug
path('phonemodel/<slug:slug>/', views.ModelView.as_view(), name='modellist'),
path('details/<slug:slug>/', views.ReviewView.as_view(), name='details'),
Now in template instead of id
<li>{{ phonemodel.model_name }}</li>
And it's better to have unique slug field
slug = models.SlugField(max_length=150, unique=True)
Also I will suggest you to use the django-autoslug. It is a reusable Django library that provides an improved slug field which can automatically populate itself from another field.
EDIT:You haven't passed context_object_name in your detail view so provide the context here
class ModelView(generic.DetailView):
model = PhoneModel
template_name = 'PhoneReview/phonemodel.html'
context_object_name= 'phonemodel'
I am a beginner in Django. I am building a Django app, named PhoneReview. It will store reviews related to the latest mobile phone. It will also display phone brands, along with the associated phone models.
I have already created models and views. I have also managed to add clickable link in the first template (brandlist.html). In the first template, when you click on the brand name, like Samsung, you will be taken to the page of the phone model, like Galaxy S10.
Here is the screenshot of the first template:
When you click the link, you will be taken to the second template (phonemodel.html). But now, I am facing an issue. There is no clickable link on the phone model ("Galaxy S10") that will direct you to details.html. Here is the screenshot.
Here are the codes of models.py inside the "PhoneReview" folder:
from django.db import models
from django.template.defaultfilters import slugify
# Create your models here.
class Brand(models.Model):
brand_name = models.CharField(max_length=100)
origin = models.CharField(max_length=100)
manufacturing_since = models.CharField(max_length=100, null=True, blank=True)
def __str__(self):
return self.brand_name
def save(self, *args, **kwargs):
self.slug = slugify(self.brand_name)
super().save(*args, **kwargs)
class PhoneModel(models.Model):
brand = models.ForeignKey(Brand, on_delete=models.CASCADE)
model_name = models.CharField(max_length=100)
launch_date = models.CharField(max_length=100)
platform = models.CharField(max_length=100)
def __str__(self):
return self.model_name
class Review(models.Model):
phone_model = models.ManyToManyField(PhoneModel, related_name='reviews')
review_article = models.TextField()
date_published = models.DateField(auto_now=True)
slug = models.SlugField(max_length=150, null=True, blank=True)
def __str__(self):
return self.review_article
Here are the codes of urls.py inside the "PhoneReview" folder:
from . import views
from django.urls import path
urlpatterns = [
path('index', views.BrandListView.as_view(), name='brandlist'),
path('phonemodel/<int:pk>/', views.ModelView.as_view(), name='modellist'),
path('details/<int:pk>/', views.ReviewView.as_view(), name='details'),
]
Here are the codes of views.py inside the "PhoneReview" folder:
from django.views import generic
from .models import Brand, PhoneModel, Review
class BrandListView(generic.ListView):
template_name = 'PhoneReview/brandlist.html'
context_object_name = 'all_brands'
def get_queryset(self):
return Brand.objects.all()
class ModelView(generic.DetailView):
model = PhoneModel
template_name = 'PhoneReview/phonemodel.html'
class ReviewView(generic.DetailView):
model = Review
template_name = 'PhoneReview/details.html'
Here are the codes of apps.py inside the "PhoneReview" folder:
from django.apps import AppConfig
class PhonereviewConfig(AppConfig):
name = 'PhoneReview'
Here are the codes of details.html inside the "templates" folder:
{% extends 'PhoneReview/base.html' %}
{% load static %}
<html>
<link rel="stylesheet" type="text/css" href="{% static "css/style.css" %}">
<html lang="en">
{% block title%}Details{% endblock %}
{% block content %}
<h1>This is the Details Page</h1>
<h2>Review:</h2>
<p>{{ review.review_article }}</p>
<h2>News Link:</h2>
<p>{{ review.slug }}</p>
{% endblock %}
</html>
Here are the codes of phonemodel.html inside the "templates" folder:
{% extends 'PhoneReview/base.html' %}
{% load static %}
{% block title%}
Phone Model Page
{% endblock %}
{% block content %}
<!--Page content-->
<h1>This is Phone Model Page</h1>
<h2>Here is the phone model</h2>
<ul>
<li>{{ phonemodel.model_name }}</li>
</ul>
<img src="{% static "images/brandlist.jpg" %}" alt="Super Mario Odyssey" /> <!-- New line -->
{% endblock %}
I tried replacing <li>{{ phonemodel.model_name }}</li> with <li>{{ phonemodel.model_name }}</li>. But I get an error, which looks like this:
NoReverseMatch at /phonemodel/1/
Reverse for 'details' with arguments '('',)' not found. 1 pattern(s) tried: ['details/(?P<pk>[0-9]+)/$']
How can I fix the issue?
There is no context variable named brand and you don't need it anyway. You should use the id of the phonemodel:
<li>
<a href = "{% url 'details' phonemodel.id %}">
{{ phonemodel.model_name }}
</a>
</li>
This is my models.py
class Post(models.Model):
topic = models.CharField(max_length=200)
description = models.TextField()
created_by = models.ForeignKey(User, related_name='posts')
created_on = models.DateTimeField()
class Comment(models.Model):
commented_by = models.ForeignKey(User, related_name='comments')
commented_on = models.ForeignKey(Post, related_name='comments')
commented_text = models.CharField(max_length=500)
commented_time = models.DateTimeField(auto_now_add=True)
class Blogger(models.Model):
username = models.OneToOneField(User, related_name='bloggers')
blogger_bio = models.CharField(max_length=1000)
URL.py for username
url(r'^(?P<username>[a-zA-Z0-9]+)/$', views.author_desc, name='author_desc'),
Views.py
from django.shortcuts import render, get_object_or_404
from .models import Post, User, Comment, Blogger
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
def home(request):
posts_list = Post.objects.all()
return render(request, 'home.html', {'posts': posts})
and my home.html where i want to display:
<!DOCTYPE html>
<html>
<head>
<title>HOME</title>
</head>
<body>
<h2>All Blogs</h2>
{% for post in posts %}
<b>Post Topic: </b>{{ post.topic }}</br>
<b>Published Time: </b>{{ post.created_on }}</br>
<b>Author: </b>{{ post.created_by }}</br></br>
{% endfor %}
</body>
</html>
I want to show each blogger's page from a link from the home. But it is getting problem.
What i'm doing wrong here?
Check whether blogger.username parameter is empty.
Infact the models are not looking that good. The ForeignKey in the Post model should be to the Blogger model.
class Post(models.Model):
created_by = models.ForeignKey(Blogger, related_name='posts')
Then in the template you can do
{% for post in posts %}
<b>Post Topic: </b>{{ post.topic }}</br>
<b>Published Time: </b>{{ post.created_on }}</br>
<b>Author: </b>{{ post.created_by.user }}</br></br>{% endfor %}
Try this
{% for post in posts %}
<b>Post Topic: </b>{{ post.topic }}</br>
<b>Published Time: </b>{{ post.created_on }}</br>
<b>Author: </b>{{ post.created_by }}</br></br>
{% endfor %}