QuerySet in Django 2.0. doesnt work - python

I had a little break in Django and today I decided to come back to this framework. But now I have a problem with elementary thinks.
I want to complete one of the guides in polish language. I've install Django 2.0 and I created some things like this:
models.py
from django.db import models
from django.utils import timezone
class Post(models.Model):
author = models.ForeignKey('auth.User',
on_delete=models.CASCADE,
)
title = models.CharField(max_length=200)
text = models.TextField()
created_date = models.DateTimeField(
default=timezone.now
)
published_date = models.DateTimeField(
blank = True, null = True
)
def publish(self):
self.published_date = timezone.now()
self.save
def __str__(self):
return self.title
project urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path(r'', include('blogs.urls')),
]
app urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.post_list, name='post_list'),]
views.py
from django.shortcuts import render
from django.utils import timezone
from .models import Post
def post_list(request):
posts = Post.objects.order_by('title','published_date').first()
return render(request, 'blogs/post_list.html', {})
and post_list.html
<div>
<h1>My blog</h1>
</div>
{% for post in posts %}
<div>
<p>published: {{ post.published_date }}</p>
<h1>{{ post.title }}</h1>
<p>{{ post.text|linebreaksbr }}</p>
</div>
{% endfor %}
Prompt do not receive any errors, but when I checking the localhost:8000 I have only a <h1> text. I have tried many solutions but still nothing. I don't know why QuerySet in %for% doesn't work. Any solutions? Did something change from Django 1.10 to 2.0?

In views.py add,
from django.shortcuts import render
from django.utils import timezone
from .models import Post
def post_list(request):
#Remove .first() as it only returns one object
posts = Post.objects.order_by('title','published_date')
#You have to create a dictionary and pass it to render
context = {
"posts" : posts ,
}
return render(request, 'blogs/post_list.html', context=context)

The queryset method first() returns a single object, the first one in the order. You cannot iterate over a single thing, but you are trying to do just that in your template. Either remove the first() and send all the objects, or remove the for loop in the template and just output the single object itself.

Related

For some reason {{ post.message }} is not displaying the modle

I am making a simple site to experiment with manipulating user data. I have a form where the user enters in some info and once they hit submit they get redirected to a new page. On this new page, the info they entered is supposed to be displayed. I am under the impression that you use this {{ Modle_Name.Fild_name}} to inject the info into the HTML. However, it is not working. If any of y'all have a solution I would much appreciate it.
sucseus.html
{% extends "base.html" %}
{% block content %}
<h1>success</h1>
<h2>{{ post.message }}</h2>
{% endblock %}
views.py
from django.shortcuts import render
from django.urls import reverse_lazy
from django.views import generic
from . import forms
from forums_simple.models import Post
# Create your views here.
class Form(generic.CreateView):
model = Post
template_name = 'forums_simple/form.html'
fields = ['message']
success_url = reverse_lazy('forums:sucsseus')
class Sucsessus_view(generic.TemplateView):
template_name = 'forums_simple/sucseus.html'
model = Post
models.py
from django.db import models
# Create your models here.
class Post(models.Model):
message = models.TextField(blank=True, null=False)
created_at = models.DateTimeField(auto_now=True)
You need to pass it as a context. The best way to do it is via DetailView.
class Sucsessus_view(generic.DetailView):
template_name = 'forums_simple/sucseus.html'
model = Post
urls:
urlpatterns = [
...
path('post/<int:pk>/', Sucsessus_view.as_view(), name='sucsseus'),
...
]
here are my URLs
from django.contrib import admin
from django.urls import path, include
from . import views
app_name = 'forums'
urlpatterns = [
path('sucseuss/<int:pk>/', views.Sucsessus_view.as_view(), name='working'),
path('forum/', views.Form.as_view(), name='form')
]

NoReverseMatch at /add_post

I have been working on a blog site using django and I made a way to add post within the home page without going to the admin page but when I post using the new way I get this error
This is my models.py file
from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse
class Post(models.Model):
title = models.CharField(max_length=255)
title_tag = models.CharField(max_length=255)
author = models.ForeignKey(User, on_delete=models.CASCADE)
body = models.TextField(max_length=3500)
def __str__(self):
return (self.title + " | " + str(self.author))
def get_absolute_url(self):
return reverse("article-view", args=(str(self.id)))
This is the views.py file
from django.views.generic import ListView, DetailView, CreateView
from .models import Post
class HomeView(ListView):
model = Post
template_name = "home.html"
class ArticleDetailView(DetailView):
model = Post
template_name = "detail_view.html"
class AddPostView(CreateView):
model = Post
template_name = "add_post.html"
fields = "__all__"
This is the polls/urls.py
from django.urls import path
from .views import HomeView, ArticleDetailView, AddPostView
urlpatterns = [
path('', HomeView.as_view(), name='home'),
path('article/<int:pk>', ArticleDetailView.as_view(), name='article-view'),
path('add_post/', AddPostView.as_view(), name='add_post'),
]
This is the add_post.html file
{% extends 'base.html' %}
{% block content %}
<head>
<title>Adding Post</title>
</head>
<h1>Add Blog Posts</h1>
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<button class="btn btn-secondary">Post</button>
</form>
{% endblock %}
Thank you.
Okay, so it looks like this is caused by the model's get_absolute_url reverse args=(). I changed the below code in models.py from:
def get_absolute_url(self):
return reverse("article-view", args=(str(self.id)))
Into
def get_absolute_url(self):
return reverse("article-view", args=[self.id])
The problem seems to be args=(), it is iterating over the str(self.id). So id=10 would actually be returned as a tuple (1,0). I also removed the str() around the self.id since the URL takes in an int.

Adding UUIDs to my Django app yields a NoReverseMatch error

I have a books app using a UUID with a listview of all books and detailview of individual books. I keep getting the following error message:
NoReverseMatch at /books/
Reverse for 'book_detail' with arguments '('/books/71fcfae7-bf2d-41b0-abc8-c6773930a44c',)' not found. 1 pattern(s) tried: ['books/(?P<pk>[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$']
Here is the models.py file:
# books/models.py
import uuid
from django.db import models
from django.urls import reverse
class Book(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
title = models.CharField(max_length=200)
author = models.CharField(max_length=200)
price = models.DecimalField(max_digits=6, decimal_places=2)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('book_detail', args=[str(self.id)])
The urls.py file where I'm using to convert the id from the model to a uuid.
# books/urls.py
from django.urls import path
from .views import BookListView, BookDetailView
urlpatterns = [
path('', BookListView.as_view(), name='book_list'),
path('<uuid:pk>', BookDetailView.as_view(), name='book_detail'),
]
The top-level urls.py file looks like this and adds a books/ route.
# urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', include('books.urls')),
The views.py file:
from django.views.generic import ListView, DetailView
from .models import Book
class BookListView(ListView):
model = Book
context_object_name = 'book_list'
template_name = 'books/book_list.html'
class BookDetailView(DetailView):
model = Book
context_object_name = 'book'
template_name = 'books/book_detail.html'
And the relevant templates file.
<!-- templates/book_detail.html -->
{% extends '_base.html' %}
{% block content %}
{% for book in book_list %}
<div>
<h2>{{ book.title }}</h2>
</div>
{% endfor %}
{% endblock content %}
I believe I'm implementing this correctly but the URL is not liking my UUID. What is amiss?
The problem is not "adding uuid". The problem is that you are doing the URL reversal twice: once in get_absolute_url and once in the {% url %} tag. Use one or the other, not both.
Either:
{{ book.title }}
Or:
{{ book.title }}

How to access pk in views (Django)

I'm writing a small chat programm in Django but have problems getting any further.
Here's the code:
models.py
from django.db import models
from datetime import datetime
from django.utils import timezone
class Chat(models.Model):
chatname = models.CharField(max_length=100)
description = models.TextField()
created_at = models.DateTimeField(default=datetime.now, blank=True)
def __str__(self):
return self.chatname
class Comment(models.Model):
chat = models.ForeignKey(Chat, on_delete=models.CASCADE)
commenter = models.CharField(max_length=30)
comment = models.TextField()
created_at = models.DateTimeField(default=datetime.now, blank=True)
def __str__(self):
return self.comment
urls.py
from django.conf.urls import url
from . import views
from django.views.generic import ListView
from chat.views import CommentList
app_name = 'chats'
urlpatterns = [
url(r'^$', views.index, name="index"),
url(r'^comments/(?P<pk>[0-9]+)/$', views.CommentList.as_view(), name='comments'),
]
views.py
from django.shortcuts import render, redirect
from django.http import HttpResponse
from django.contrib.auth import authenticate, login
from django.views import generic
from .models import Chat, Comment
def index(request):
username = None
if request.user.is_authenticated():
username = request.user.username
chats = Chat.objects.all()[:10]
context = {
'chats':chats
}
return render(request, 'chat/index.html', context)
class CommentList(generic.ListView):
queryset = Comment.objects.filter(chat_id=1)
context_object_name = 'comments'
My comment_list.html
{% extends "chat/base.html" %}
{% block content %}
Go back
<h3>Comments</h3>
<h2>{{chat.id}}</h2>
<ul>
{% for comment in comments %}
<li>{{ comment.commenter }}: {{ comment.comment }}</li>
{% endfor %}
</ul>
{% endblock %}
My database structure contains these two models: Chat and Comment. Each chat(room) is supposed to have its own comments. I used 'models.ForeignKey' to be able to filter the comments for each chat(room). In my index.html I list all the chats and each of these has a hyperlink to the /comments/ section.
In my views.py I have this line: 'queryset = Comment.objects.filter(chat_id=1)'
Chat_id is the column in the comments sql table and as it is now it will only show comments that belong to the chat with pk=1. How can I auto access the chat for the different urls /comments/1/ /comments/2/ and so on..?
Hope the explanation is clear. Sorry beginner here, I can try to explain further if it doesn't make a lot of sense.
Best,
Fabian
You should define the get_queryset method instead of the standalone queryset attribute.
def get_queryset(self, *args, **kwargs):
return Comment.objects.filter(chat_id=self.kwargs['pk'])
Instead of CommentList you can use plain view:
def comments_index(request, chatid):
return render(request, 'xxx/comment_list.html', {
'comments': Comment.objects.filter(chat_id=chatid)
})
And in urls:
url(r'^comments/(?P<chatid>[0-9]+)/$', views.comments_index, name='comments'),

How to manipulate database info before displaying it in Django template?

So I've got a basic Django website setup that displays dynamic info from the database.
I would like to be able to manipulate the text coming out of the database so I can create BBCode parsers or whatever else I want. I'm pretty new to Django so I'm a little confused as to where this should be done.
These are my files so far...
Models.py
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=140)
body = models.TextField()
date = models.DateTimeField()
def __str__(self):
return self.title
Urls.py
from django.conf.urls import url, include
from django.views.generic import ListView, DetailView
from forum.models import Post
urlpatterns = [
url(r'^$', ListView.as_view(queryset=Post.objects.all().order_by("-date")[:25], template_name="forum/forum.html")),
url(r'^(?P<pk>\d+)$', DetailView.as_view(model = Post, template_name = 'forum/post.html')),
]
Forum.html
{% extends "layout.html" %}
{% block body %}
{% for post in object_list %}
<p>{{ post.date|date:"Y-m-d" }} {{ post.title }}</p>
{% endfor %}
{% endblock %}
Functions.py
def bbcode(data):
data2 = data + "some random text"
return data2
All of those files are located inside of the "forum" directory located in the root project folder which is "coolsite".
So my understanding is that I need to import functions.py somewhere and use the bbcode() method to manipulate text being pulled from the database. That way it has been parsed once displayed on the "forum.html" template.
Sorry if this is a duplicate question. I searched around and couldn't quite find what I was looking for.
How should I go about doing this exactly?
You need to override the ListView methods. You will need to do some changes in your code:
Set a custom view to your url config
urls.py
from django.conf.urls import url, include
from django.views.generic import ListView, DetailView
from forum.models import Post
from forum.views import PostList
urlpatterns = [
url(r'^$', PostList.as_view(), name='post_list'),
url(r'^(?P<pk>\d+)$', DetailView.as_view(model = Post, template_name = 'forum/post.html')),
]
Create a custom view in your app (forum.views) based in a ListView
# views.py
from django.views.generic import ListView
from forum.models import Post
class PostList(ListView):
model = Post
template_name = "forum/forum.html"
# here is where magic happens
def get_context_data(self, *args, **kwargs):
context = super(PostList, self).get_context_data(*args, **kwargs)
# context has the same context that you get in your template before
# so you can take data and work with it before return it to template
return context
You can found docs for Class-Based Views here

Categories