Problem:
I am trying to simply iterate over my Category model and display a list of categories. I've successfully done so with posts, but for some reason I can't get it to work with my categories model (It doesn't even make it passed the {% if categories %} statement). Thus, the <h2>Categories:</h2> and below is not rendered at all.
I currently have two categories in my database ('Fitness' and 'Nutrition'). They are in my admin, and they also show up when I query through the command line. I can also successfully link to them from my 'post_detail' page (and display all posts within a category). However, I can't seem to iterate over the model to display all categories as a list...
Code:
post_list.html
<div class="container">
<h2>Categories:</h2>
{% if categories %}
<h2>Categories</h2>
<ul>
{% for category in categories %}
<li>{{ category.name }}</li>
{% endfor %}
</ul>
{% endif %}
</div>
models.py
from django.db import models
from django.utils import timezone
from django.template.defaultfilters import slugify
class Category(models.Model):
name = models.CharField(max_length=255, blank=False, default='')
slug = models.SlugField(max_length=100, default='', unique=True)
class Meta:
verbose_name = "Category"
verbose_name_plural = "Categories"
ordering = ['name']
def __str__(self):
return self.name
def __unicode__(self):
return self.name
views.py
from .models import Post, Category
from .forms import PostForm
from django.shortcuts import redirect
from django.db.models import Count
def category_detail( request, slug ):
category = get_object_or_404( Category, slug= slug )
context = {
'category': category,
'posts': category.post_set.all()
}
return render( request,'blog/category_detail.html', context )
def post_list(request):
posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
context = {
'categories': getSortedCategories()
}
return render(request, 'blog/post_list.html', {'posts': posts})
urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.post_list, name='post_list'),
url(r'^(?P<slug>[-\w]+)/$', views.category_detail, name='category_detail'),
url(r'^post/(?P<pk>\d+)-(?P<slug>[-\w]+)/$', views.post_detail, name='post_detail'),
url(r'^post/new/$', views.post_new, name='post_new'),
url(r'^post/(?P<pk>\d+)/edit/$', views.post_edit, name='post_edit'),
]
You do not transmit categories in the template context, you need to rewrite return expression like this:
return render(request, 'blog/post_list.html', {'posts': posts, 'categories': getSortedCategories()})
Related
I want to add like unlike feature to my blog site, everythin is okay there, like and unlike objects are being created.. But I'm getting NoReverseMatch when I'm clicking the Like and Unlike..and the problem is I can't figure it out why I'm getting this...my models.py, views.py, urls.py, blog_page.html...all are attatched here..
plz try help me solve this
**models.py**
from email.policy import default
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Blog(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=200, verbose_name="Put a Title")
blog_content = models.TextField(verbose_name="What is on your mind")
blog_image = models.ImageField(upload_to="blog_images", default = "/default.png")
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
class Comment(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE, related_name = "blog_comment" )
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name = "user_comment")
comment = models.TextField()
comment_date = models.DateField(auto_now_add=True)
def __str__(self):
return self.comment
class Like(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE, related_name = "blog_liked")
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name = "user_liked")
class Unlike(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE, related_name = "blog_unliked")
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name = "user_unliked")
**views.py**
from django.shortcuts import render
from . models import Blog, Comment, Like, Unlike
# Create your views here.
def home(request):
blogs = Blog.objects.all()
context = {'blogs': blogs}
return render(request, 'blog_app/home.html', context)
def blog_view(request, pk):
blog = Blog.objects.get(id=pk)
context = {"blog": blog}
return render(request, 'blog_app/blog_page.html', context)
def like(request, pk):
blog = Blog.objects.get(id=pk)
user = request.user
liked, like = Like.objects.get_or_create(blog=blog, user=user)
context = {"liked" : liked}
return render(request, "blog_app/blog_page.html", context)
def unlike(request, pk):
blog = Blog.objects.get(id=pk)
user = request.user
unliked, unlike = Unlike.objects.get_or_create(blog=blog, user=user)
context = {"unliked" : unliked}
return render(request, "blog_app/blog_page.html", context)
**urls.py**
from django.urls import path
from blog_app import views
urlpatterns = [
path("", views.home, name='home'),
path("blog_page/<str:pk>/", views.blog_view, name='blog_page'),
path("like/<str:pk>/", views.like, name="like"),
path("unlike/<str:pk>/", views.unlike, name="unlike"),
]
**blog_page.html**
{% extends "main.html" %}
{% load static %}
{% block content %}
<div style="text-align:center;">
<h2>{{blog.title}}</h2>
<img src="{{blog.blog_image.url}}" alt="" width="630px" height="300px">
</div>
<div style="text-align:center;">
{{blog.blog_content|linebreaks}}
</div>
{% if liked %}
<h4>Unlike</h4>
{% else %}
<h4> Like </h4>
{% endif %}
{% endblock content %}
Your URLs are expecting a string value for blog_id but you are passing them an int in {% url 'unlike' blog.id %} Try changing your URL file to expect an int, and you should be able to look it up more successfully.
path("blog_page/<int:pk>/", views.blog_view, name='blog_page'),
path("like/<int:pk>/", views.like, name="like"),
path("unlike/<int:pk>/", views.unlike, name="unlike"),
Also, as you are using the same page template for the like and unlike view, you will need to pass the blog element in the context again to make links work on those pages, eg,
context = {"liked" : liked, "blog", blog}
I am building a web app in Django trying to use django-autocomplete-light(v.3.8.2) to create an auto-complete field. I have form that allows users to create a Trade record. I'm trying to add an auto-complete field for Trade.owned_game (a lookup field). I am just getting an empty dropdown field for the auto-complete field (screenshot attached at bottom of this post) Below is my code:
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 Game(models.Model):
name = models.TextField() # Unrestricted text
platform = models.CharField(max_length=100) # character field
created_date = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.name # return game name when game.objects.all() is called
class Trade(models.Model):
name = models.TextField() # Unrestricted text
created_date = models.DateTimeField(default=timezone.now)
is_trade_proposed = models.BooleanField(default=False)
user_who_posted = models.ForeignKey(User, on_delete=models.CASCADE)
owned_game = models.ForeignKey(Game, on_delete=models.CASCADE, related_name='owned_game', db_column='owned_game')
def __str__(self):
return self.name # return game name when game.objects.all() is called
urls.py:
from django.urls import path
from django.conf.urls import url
from .views import (
PostListView,
TradeListView,
PostDetailView,
TradeCreateView,
GameAutoComplete,
PostUpdateView,
PostDeleteView,
UserPostListView
)
from . import views
urlpatterns = [
path('', views.home, name='blog-home'),
path('post/new/', views.trade_new, name='trade-create'),
url(
r'^game-autocomplete/$',
GameAutoComplete.as_view(),
name='game-autocomplete')
,
]
views.py:
from django.shortcuts import render, get_object_or_404
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.contrib.auth.models import User
from django.views.generic import (
ListView,
DetailView,
CreateView,
UpdateView,
DeleteView
)
from .models import Trade, Game
def trade_new(request):
form = TradeCreateForm()
return render(request, 'blog/trade_form.html', {'form': form, 'title': 'asdf'})
class TradeCreateForm(forms.ModelForm):
game = forms.ModelChoiceField(
queryset=Game.objects.all(),
to_field_name = 'name',
widget=autocomplete.ModelSelect2(url='game-autocomplete')
)
class Meta:
model = Trade
fields = ['owned_game', 'desired_game']
class TradeCreateView(LoginRequiredMixin, CreateView):
model = Trade
fields = ["owned_game"]
class GameAutoComplete(autocomplete.Select2QuerySetView):
def get_queryset(self):
if not self.request.user.is_authenticated:
return Game.objects.none()
qs = Game.objects.all()
if self.q:
qs = qs.filter(name__istartswith=self.q)
return qs
trade_form.html:
{% extends "blog/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Propose New Trade</legend>
{{ form|crispy }}
{{ form.media }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Submit</button>
</div>
</form>
</div>
{% endblock content %}
Screenshot:
enter image description here
I have tried the solutions from these similar StackOverflow questions but they're not working:
Django-autocomplete-light showing empty dropdown instead of autocomplete widget
django-autocomplete-light displays empty dropdown in the form
I should have checked the javascript console earlier! The problem was one of the <link ...> scripts for jQuery was invalid. Once i fixed that, the auto-complete field worked
I'm new to Django and have build a simple application that includes posts. I want to display posts that are associated with certain categories on one page. I did quite a bit of research online but can't seem to make it work. I think the problem is in my views.py
I guess there's something wrong with the get_queryset function in CategoryListView.
'''
models.py
'''
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
date = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
category = models.ForeignKey(
'Category',
on_delete=models.SET_NULL,
null=True)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk': self.pk})
class Category(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField(max_length=150, unique=True)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('post-category', kwargs={'pk': self.pk})
'''
views.py
'''
from django.views.generic import ListView
from .models import Post, Category
class CategoryListView(ListView):
model = Post
template_name = 'posts/post_category.html'
def get_queryset(self):
category = get_object_or_404(Category, id=self.kwargs.get('category__name'))
return Posts.objects.filter(category_name=category)
'''
urls.py
'''
from .views import CategoryListView
urlpatterns = [
# urlpatterns for other pages left out for better readability
CategoryListView.as_view(), name='post-category')
]
The code gives me a 404 and the message that no Category matches my query.
The get_queryset [Django-doc] function should return something like:
class CategoryListView(ListView):
# ...
def get_queryset(self):
return Post.objects.filter(category_id=self.kwargs.get('pk'))
Furthermore in your url, you will need to use a pattern with a pk parameter, like:
urlpatterns = [
path('category/<int:pk>', CategoryListView.as_view(), name='post-category')
]
That being said, if you want to display information about the category, it might make more sense to make it a DetailView [Django-doc], and then query the relation in reverse, like:
class CategoryDetailView(DetailView):
model = Category
context_object_name = 'category'
template_name = 'posts/post_category.html'
and in the template, you can render data with:
Category name: {{ category.name }}
{% for post in category.post_set.all %}
post: {{ post.title }}
{% endfor %}
This works, but how dow I reverse the order of it to always show the latest post first?
Category name: {{ category.name }}
{% for post in category.post_set.all %}
post: {{ post.title }}
{% endfor %}
I have a problem where I can't use my Django variables inside Html
This is my code :
models.py
from django.db import models
from django.urls import reverse
# Create your models here.
class Post(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField(max_length=255, unique=True)
created = models.DateTimeField(auto_now_add=True)
content = models.TextField(default="---")
H_price = models.IntegerField(default=0)
L_price = models.IntegerField(default=0)
remaining = models.IntegerField(default=0)
original_price = models.IntegerField(default=0)
Ended = models.BooleanField(default=False)
Published = models.BooleanField(default=True)
class Meta:
ordering = ['-created']
def __unicode__(self):
return u'%s'% self.title
def get_absolute_url(self):
return reverse('Products.views.post', args=[self.slug])
Views.py
from django.shortcuts import render
from .models import Post
# Create your views here.
def index(request):
posts=Post.objects.all()
return render(request, 'Index.html', {"Posts": posts})
def post(request):
return
Index.html
<h1>This is just a title </h1>
{% for post in posts %}
<div>
<h3> {{ post.title }}</h3>
<h3> {{ post.content }}</h3>
</div>
{% endfor %}
I know this isn't the best way to do Html but the goal is just to get it to work then I will style it with css and make everything Look Clean When i run the server i only get "this is just a title"
Any suggestions to help me fix it will be apreciated
Note that I am a begginer in django
Variables in the Django template language are case sensitive. You use {% for post in posts %} in your template, therefore you need to use posts not Posts in your view.
return render(request, 'Index.html', {"posts": posts})
I'm learning django framework writing a blog. I've added some posts in django-admin and I want to show them on web.
MODELS.PY
from django.db import models
from django.utils import timezone
from django.core.urlresolvers 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', 'Roboczy'),
('publish', 'Opublikowany')
)
title = models.CharField(max_length=300)
slug = models.SlugField(max_length=300, 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=20,
choices=STATUS_CHOICES,
default='draft')
object = 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.strftime('%m'),
self.publish.strftime('%d'),
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, year, month, day, post):
post = get_object_or_404(Post, slug=post,
status ='published',
publish_year=year,
publish_month=month,
publish_day=day)
return render(request,
'blog/post/detail.html',
{'post': post})
URLS.PY at BLOG APP
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.post_list, name='post_list'),
url(r'^(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/$'
r'(?P<post>[-\w]+)/$',
views.post_detail,
name='post_detail'),
]
URLS.PY (project level)
from django.conf.urls import include, url
from django.contrib import admin
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^blog/', include('blog.urls',
namespace='blog',
app_name='blog')),
]
list.html
{% extends "blog/base.html" %}
{% block title %}My Blog {% endblock %}
{% block content %}
<h1>Mój BLOG</h1>
{% for post in posts %}
<h2>
<a href="{{ post.get_absolute_url }}">
{{ post.title }}
</a>
</h2>
<p>
Opublikowane {{ post.publish }} przez {{ post.author }}
</p>
{{ post.body|truncatewords:30|linebreaks}}
{% endfor %}
{% endblock %}
I don't know why these posts aren't shown on list.html. I think the mistake is in get_absolute_url.
Instead of posts = Post.published.all()
Try
posts = Post.objects.all()
Ok it's work i must change posts = Post.objects.all() and on list.htlm
<a href="{{ post.get_absolute_url }}">
to
<a href="{{ posts }}">
Urlpatterns are wrong.
url(r'^(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/$'
r'(?P<post>[-\w]+)/$',
views.post_detail,
name='post_detail'),
According to the views the url pattern should be:
url(r'^(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/(?P<post>[-\w]+)/$',
views.post_detail,
name='post_detail'),
Also, Views are wrong:
def post_detail(request, year, month, day, post):
post = get_object_or_404(Post, slug=post,
status ='published',
publish__year=year,
publish__month=month,
publish__day=day)
return render(request,
'blog/post/detail.html',
{'post': post})
Please note that query fields are publish__year (not publish_year), publish___month(not publish_month) and publish__date( not publish_date)
Once you make these changes, the get_absolute_url will also work fine.
I don't know if you want to use Post.objects.all() or Post.published.all(). Ideally, it should be Post.published.all() because in general, only published posts are displayed.