get_absolute_url is not changing template? - python

get_absolute_url is redirecting to the page im already on (forum_list.html instead of thread_list.html)?
models.py
class Thread(models.Models):
(...)
def get_absolute_url(self):
return reverse('forum:thread_list',
args=[self.created.year,
self.created.month,
self.created.day,
self.slug])
urls.py
path('<int:year>/<int:month>/<int:day>/<slug:slug>/',
views.ThreadListView.as_view(), name='thread_list'),
views.py
class ThreadListView(ListView):
querytext = Thread.published.all()
context_object_name = 'threads'
paginate_by = 20
template_name = 'forum/thread_list.html'
forum_list.html
{% extends 'forum/base.html' %}
{% block content %}
<a href="{{ forum.get_absolute_url }}>Read</a>"
{% endblock content %}
what am i doing wrong?
the url in the adress bar changes but the template doesnt..
It refreshes the same page but the URL changes.

Related

Django python: no such column:

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

Django: post form and post list on the same page

I make a site with multiple users, making posts with images and ability to add/remove friends.
So it's easy to make two different pages for post list and creating a new one. But of course it looks better when you can read posts and make new at the same place.
As I understand (learn django for less than a month), I can't connect 2 views to the same url, so the most logical way I see is to join 2 views in one, I also tried to play with template inheriting to render post form by including template, but actually it doesn't work.
Below you can see my views, Post model, and templates. Thank you for attention.
views.py:
from braces.views import SelectRelatedMixin
from . import models
from django.views import generic
from django.contrib.auth.mixins import LoginRequiredMixin
class PostList(SelectRelatedMixin, generic.ListView):
model = models.Post
select_related = ('user',)
class CreatePost(LoginRequiredMixin, SelectRelatedMixin, generic.CreateView):
fields = ('post_message', 'post_image')
model = models.Post
select_related = ('user',)
def form_valid(self, form):
self.object = form.save(commit = False)
self.object.user = self.request.user
self.object.save()
return super().form_valid(form)
models.py:
import misaka
class Post(models.Model):
user = models.ForeignKey(User, on_delete = models.CASCADE, related_name = 'posts')
posted_at = models.DateTimeField(auto_now = True)
post_message = models.TextField()
message_html = models.TextField(editable = False)
post_image = models.ImageField(upload_to = 'postpics', blank = True)
def __str__(self):
return self.post_message
def save(self, *args, **kwargs):
self.message_html = misaka.html(self.post_message)
super().save(*args, **kwargs)
def get_absolute_url(self):
return reverse('posts:all')
class Meta:
ordering = ['-posted_at']
unique_together = ['user', 'post_message']
urls.py:
app_name = 'posts'
urlpatterns = [
path('', views.PostList.as_view(), name = 'all'),
path('new/', views.CreatePost.as_view(), name = 'create'),
]
post_form.html (template, that allows to make a new post, which will be seen in post_list.html):
{% extends 'posts/post_base.html'%}
{% block post_content %}
<div class="post-form">
<form action="{% url 'posts:create' %}" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<p>{{ form.post_message }}</p>
<p>{{ form.post_image }}</p>
<input id='post-submit' type="submit" value="Post">
</form>
</div>
{% endblock %}
post_list.html:
{% extends 'posts/post_base.html'%}
{% block post_content %}
<div class="post-container">
{% for post in post_list %}
<div class="current-post-container">
{% include 'posts/_post.html'%}
</div>
{% endfor %}
</div>
{% endblock %}
_post.html(pages, which render by Misaka):
<div class="post-info">
<h5 id='post-owner' >{{post.user.first_name}} {{post.user.last_name}}</h5>
<h6>{{ post.posted_at }}</h6>
<p>{{ post.message_html|safe }}</p>
<div>
<img class='post-image' src="/media/{{ post.post_image }}" alt="">
<div>
{% if user.is_authenticated and post.user == user and not hide_delete %}
<a href="{% url 'posts:delete' pk=post.pk %}" title = 'delete'>Delete</a>
{% endif %}
</div>
</div>
</div>
post_base.html:
{% extends 'base.html' %}
{% block content%}
{% block prepost %}{% endblock %}
{% block post_content %}{% endblock %}
{% block post_post %}{% endblock %}
{% endblock %}
EDIT:
Task was solved. I added two template_name strings to both of my views, so now they look like:
CreatePost in views.py:
class CreatePost(LoginRequiredMixin, SelectRelatedMixin, generic.CreateView):
fields = ('post_message', 'post_image')
model = models.Post
select_related = ('user',)
template_name = 'posts/post_list.html'
template_name = 'posts/post_form.html'
def form_valid(self, form):
self.object = form.save(commit = False)
self.object.user = self.request.user
self.object.save()
return super().form_valid(form)
PostList in views.py:
class PostList(SelectRelatedMixin, generic.ListView):
model = models.Post
select_related = ('user',)
template_name = 'posts/post_list.html'
template_name = 'posts/post_form.html'
You can put the post_create_form on the same page as post_list_view there is no need to make a separate view for post creation but You need to make ones for editing and deleting.
You can give all of these views the same HTML page with different URLs.
Using template_name = 'example/example.html' ,in Class_Based_Views.
I hope I understand your problem if not clarify more why you can't join two views in one.
def posts(request):
posts = Post.objects.all()
form = PostForm(request.POST or None, request.FILES or None)
if request.method == "POST":
if form.is_valid():
...
context={
'posts' : page_obj,
'create_or_update_post_form' : form,
}
return render(request, 'post/posts.html',context)
Do you struggle to do this in Class-based-view?
You can do easily with django class based views.
Create views as
from django.views.generic import ListView
from django.views.generic.edit import CreateView
class ModelCreate(CreateView):
model = ModelName
fields = ['field1', 'field2']
template_name = 'same_page.html'
success_url = reverse_lazy('list_view')
class ModelList(CreateView, ListView):
model = ModelName
fields = ['field1', 'field2']
paginate_by = 5
template_name = 'same_page.html'
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
context['form'] = self.get_form()
return context
# If form post redirect to ModelCreate View
def post(self, request, *args, **kwargs):
return ModelCreate.as_view()(request)
app/urls.py
from django.urls import path
from app import views
path('list', views.ModelList.as_view(), name='list_view'),
path('add', views.ModelCreate.as_view(), name='add_view'),
Finally in templates/same_page.html
<div class="row">
<div class="col-sm-5">
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{form.as_p}}
<button type="submit" value="submit" class="btn btn-primary btn-sm float-right">Submit</button>
</form>
</div>
<div class="col-sm-5">
{% if object_list %}
{% for object in object_list %}
<p>{{object.field1}}</p>
<p>{{object.field2}}</p>
{% endfor %}
{% endif %}
</div>
</div>
Hope, this helps.

Django comments not showing in template

I have a system setup to show comments on a post detail page, however the comments are not showing. I have been focusing on the template tags, because I have used this view code elsewhere and it has worked, however I may be wrong. No errors returning, just not showing the comment in the detail view.
userpost_detail.html:
{% extends 'base.html' %}
{% block content %}
<div class="main">
<h1 class="posttitle">{{ userpost.title }}</h1>
<p class="postcontent">{{ userpost.post_body }}</p>
{% if request.user.is_authenticated and request.user == post.author %}
<a class="link" href="{% url 'feed:edit_post' post.id %}">Edit Post</a>
{% endif %}
Add Comment
{% for comment in userpost.usercomment.all %}
{% if user.is_authenticated %}
{{ comment.create_date }}
<!--
<a class="btn btn-warning" href="{% url 'comment_remove' pk=comment.pk %}">
<span class="glyphicon glyphicon-remove"></span>
</a>
-->
<p>{{ comment.comment_body }}</p>
<p>Posted By: {{ comment.author }}</p>
{% endif %}
{% empty %}
<p>No Comments</p>
{% endfor %}
</div>
{% include 'feed/sidebar.html' %}
{% endblock %}
app PostDetailView:
class PostDetailView(DetailView):
model = UserPost
app add_comment_to_post view:
#login_required
def add_comment_to_post(request,pk):
post = get_object_or_404(UserPost,pk=pk)
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.post = post
comment.author = request.user
comment.save()
return redirect('feed:post_detail', pk=post.pk)
else:
form = CommentForm()
return render(request,'feed/comment_form.html',{'form':form})
app urls:
from django.conf.urls import url
from feed import views
app_name = 'feed'
urlpatterns = [
url(r'^new/$',views.CreatePostView.as_view(),name='new_post'),
url(r'^post/(?P<pk>\d+)$',views.PostDetailView.as_view(),name='post_detail'),
url(r'^post/(?P<pk>\d+)/edit/$',views.UpdatePostView.as_view(),name='edit_post'),
url(r'^post/(?P<pk>\d+)/delete/$',views.DeletePostView.as_view(),name='delete_post'),
url(r'^post/(?P<pk>\d+)/comment/$',views.add_comment_to_post,name='add_comment'),
]
Models.py:
from django.db import models
from django.core.urlresolvers import reverse
from django.conf import settings
from django.contrib.auth import get_user_model
User = get_user_model()
# Create your models here.
class UserPost(models.Model):
author = models.ForeignKey(User,related_name='userpost',null=True)
post_date = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=150,blank=False)
post_body = models.TextField(max_length=1000,blank=False)
def publish(self):
self.save()
def get_absolute_url(self):
return reverse('index')
def __str__(self):
return self.title
class UserComment(models.Model):
post = models.ForeignKey('feed.UserPost',related_name='comments')
author = models.ForeignKey(User,related_name='usercomment')
comment_date = models.DateTimeField(auto_now_add=True)
comment_body = models.TextField(max_length=500)
def publish(self):
self.save()
def get_absolute_url(self):
return reverse("userpost_list")
def __str__(self):
return self.comment_body
As #user6731765 mentioned you need comments coz of related_name
{% for comment in userpost.comments.all %}
When you get comment_remove error
You need to define a url for comment_remove and define a view for that.
urlpatterns = [
. . . . . .
url(r'^comment/remove/(?P<pk>\d+)/$',views.DeleteCommentView.as_view(),name='comment_remove'),
]
Then in views.py
class DeleteCommentView(DeleteView):
model=UserComment
Due to the related_name you are using for posts in UserComment, try using
{% for comment in userpost.comments.all %}
in your template instead.

Filtering Queryset and designing correct urls.py and templates in Django

I am designing a video rendering kids website.
The app has parent categories for eg: Cartoons, Education shows etc. Each category has multiple posts such as Jungle_book,Duck_tales etc for cartoons.
Each post has multiple episodes.
I am using generic views(listview, Detailview) for views.
Here are my Models.py
from django.db import models
from personal.models import Post
class cartoons_post(models.Model):
category= models.ForeignKey(Post, on_delete=models.CASCADE)
title = models.CharField(max_length = 140)
thumbnail=models.ImageField()
date=models.DateField()
def __unicode__(self):
return self.title
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("posts:detail", kwargs={"id": self.id})
class post_episode(models.Model):
post_id= models.ForeignKey(cartoons_post, on_delete=models.CASCADE)
title = models.CharField(max_length = 140)
thumbnail=models.ImageField()
date=models.DateField()
video=models.FileField()
def __unicode__(self):
return self.title
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("posts:detail", kwargs={"id": self.id})
Here is my urls.py
from django.conf.urls import url, include
from django.views.generic import ListView, DetailView
from cartoons.models import cartoons_post,post_episode
from django.contrib.auth.decorators import login_required
urlpatterns = [
url(r'^$', login_required(ListView.as_view(
queryset=cartoons_post.objects.all().order_by("-date")[:10],
template_name="cartoons/cartoons.html"))),
url(r'^(?P<pk>\d+)$', login_required(ListView.as_view(
queryset=post_episode.objects.filter(post_id=1).order_by("-date"),
template_name="cartoons/post.html"))),
url(r'^(?P<pk>\d+\d+)$',login_required(DetailView.as_view(
model = post_episode,
template_name="cartoons/post_episode.html"))),
]
Here are my three templates
cartoons.html
{% extends "personal/header.html" %}
{% load staticfiles %}
{% block content %}
{% for cartoons_post in object_list %}
<img src= "{{cartoons_post.thumbnail.url}}" width="200" height="220">
{% endfor %}
{% endblock %}
post.html
{% extends "personal/header.html" %}
{% load staticfiles %}
{% block content %}
{% for post_episode in object_list %}
<img src= "{{post_episode.thumbnail.url}}" width="200" height="220">
{% endfor %}
{% endblock %}
post_episode.html
{% extends "personal/header.html" %}
{% load staticfiles %}
{% block content %}
<div class="container-fluid_cartoons">
<h3>{{post_episode.title}}</h3>
<video width="850" height="500" controls>
<source src="{{post_episdoe.video.url}}" type="video/mp4">
Your browser does not support the video tag.
</video>
</div>
{% endblock %}
Issues
- Only cartoons.html is working fine.
Once I click on an individual post the relevant post.html shows all the episode uploaded rather than episodes pertaining to individual post only.
Once I click on an episode, nothing happens.
You should consider creating views.py file rather than using generic views in urls.py. I think issue is with following line
url(r'^(?P<pk>\d+)$',login_required(ListView.as_view(queryset=post_episode.objects.filter(post_id=1).order_by("-date"),template_name="cartoons/post.html"))),
Here, If my guess is correct, you are trying to pass id of post model from url to view. But to make ListView accept url kwargs (post_id) you have to write another view in views.py. Maybe something like below.
class EpisodeListView(ListView):
template_name = 'cartoons/post.html'
def get_queryset(self):
return post_episode.objects.filter(post_id=self.kwargs['post_id']).order_by("-date")
Then route a url to that view:
from <yourapp.views> import EpisodeListView
from django.contrib.auth.decorators import login_required
url(r'^episodes/(?P<pk>\d+)$',login_required(EpisodeListView.as_view())

How do I pass and render an object to an extended child template?

So what I'm trying to do is create a view for a child template, so that I can pass in model objects and parameters, and render it accordingly. But is this possible..because two views can't be called once? And two urls (one for child and one for parent template) can't be called at once either. I don't understand how it works or maybe I'm just not looking at it right. Does anyone have any idea?
urls.py
BV = BoxesView.as_view()
urlpatterns = [
url(r'^(?P<question_id>[0-9]+)/$', poll, name='poll'), #child template
url(r'^$', BV, name='news'), #parent template
]
view.py
class BoxesView(ListView):
template_name = 'polls.html'
def get_queryset(self):
queryset_list = Post.objects.all().filter(category=1).order_by('-date')
return queryset_list
def poll(request, question_id):
question = get_object_or_404(Question, id=1)
return render(request, 'polls.html', {'question': question})
polls.html
{% extends 'parent.html' %}
{% block polls %}
<p>question goes here</p> #this shows up
{{ question.question_text }} #this doesn't show up
{% endblock %}
parent.html
{% extends 'base.html' %}
{% block content %}
{% for post in post_list %}
{% block polls %}
{% endblock %}
{% endfor %}
{% endblock %}
models.py
class Post(models.Model):
title = models.TextField(max_length=70)
class Question(models.Model):
question_text = models.CharField(max_length=70)
urls.py
If the url to your child template is:
url(r'^(?P<question_id>[0-9]+)/$', poll, name='poll'), #child template
The view to handle request matching the above url will be handled by the poll view as mentioned in url 3 arguments are passed to it - the synopsis is:
url(<regex to match url parameters>, <view to handle the request>, <name of the url>):
views.py
def poll(request, question_id):
question = get_object_or_404(Question, id=1)
return render(request, 'polls.html', {'question': question})
Synopsis for the view's return statement:
return render(request, <template name to render>, <the context dictionary for passing anything object/python var to the template>)
as 'poll.html' is your child template, it's all set fine for you.
About passing the object to child.html - you're already passing the Question object here {'question': question},

Categories