This is my code,
I use django v3 and want convert the category functions in views.py to a list class(ListView) for use pagination.
How can do it?
Thank you alot
urls.py
from django.urls import path from .views import posts_category
urlpatterns = [
path('<slug:slug>/', posts_category, name="posts_category"),
]
model.py
class Category(models.Model):
parent = models.ForeignKey('self', blank=True, null=True, related_name='children', on_delete=models.CASCADE)
title = models.CharField(max_length=70, unique=True)
slug = models.SlugField(max_length=90, unique=True)
description = RichTextUploadingField(blank=True, null=True)
image = models.ImageField(blank=True, upload_to="imgs")
def __str__(self):
return self.title
class MPTTMeta:
order_insertion_by = ['title']
views.py
def posts_category(request, slug):
category = Category.objects.all()
post = Posts.objects.filter(category__slug=slug, status="p")
context = {
'category': category,
'post': post,
}
return render(request, 'posts_category.html', context)
I don't know if this is a good idea to show categories and products in the same page (because of the performance point of view) but you can use following code to convert your FBV to CBV:
from django.views.generic import ListView
class PostCategoryView(ListView):
template_name = 'posts_category.html'
def get_queryset(self):
slug = self.kwargs.get('slug')
return Posts.objects.filter(category__slug=slug, status="p")
def get_context_data(self, **kwargs):
context = super().get_context_data()
context['categories'] = Category.objects.all()
return context
And also change your urls to:
from django.urls import path
from .views import PostCategoryView
urlpatterns = [
path('<slug:slug>/', PostCategoryView.as_view(), name="posts_category"),
]
And finally you can use the context data in your template like the following code:
{% for obj in object_list %}
{{ obj.id }} - {{ obj.name }}</a><br>
{% endfor %}
Note that object_list is a list of your Post objects and you should change obj.name to other fields of your Post model. Finally you can use something like object_list (here we used categories) and loop through it to show the data of your categories or other things.
Related
I don't understand why information from database isn't showing in html dropdown list. I have watched many videos and tutorials, but something going wrong. Department table isn't empty. I'm using SQLite.
Here is my html template — click
And also:
models.py
from django.db import models
class Department(models.Model):
class Meta:
verbose_name_plural = 'Отделы'
department_name = models.CharField(verbose_name='Отдел', max_length=40, editable=True, unique=True)
def str(self) -> str:
return self.department_name
class User(models.Model):
class Meta:
verbose_name_plural = 'Участники'
first_name = models.CharField(verbose_name='Имя', max_length=40)
last_name = models.CharField(verbose_name='Фамилия', max_length=40)
rfid_mark = models.CharField(verbose_name='RFID', max_length=8, editable=True, unique=True)
department = models.ForeignKey(Department, on_delete=models.CASCADE)
datetime = models.DateTimeField(auto_now=True, editable=False)
def str(self) -> str:
return self.first_name + ' ' + self.last_name
views.py
from django.shortcuts import render
from .forms import UserForm
from .models import Department
def create(request):
form = UserForm()
if request.method == "POST":
form = UserForm(request.POST)
if form.is_valid():
form.save()
context = {'form': form}
return render(request, 'passage/registration.html', context)
def index(request):
query_results = Department.objects.all()
context = {'query': query_results}
return render(request,'passage/registration.html', context)
forms.py
from .models import User
from django.forms import ModelForm
class UserForm(ModelForm):
class Meta:
model = User
fields = ['first_name', 'last_name', 'rfid_mark', 'department']
urls.py (project)
from django.contrib import admin
from django.urls import path, include
from django.conf.urls.static import static
from django.conf import settings
urlpatterns = [
path('sign_up', include('passage.urls')),
path('admin/', admin.site.urls)
] + static(settings.STATIC_URL, document_root =settings.STATIC_ROOT)
urls.py (app)
from django.urls import path
from . import views
urlpatterns = [
path('', views.create, name='user create'),
]
First you all refreshing to the wrong field as model has no department_id. , you were missing the value of the option.
The template shall be as below.
{% for result in query %}
<option value='{{ result.id }}'>{{ result.department_name }}</option>
{% endfor %}
From your code, it looks like you queried from Department Model.
See that you are trying to print {{ result.department_id }}.
But in the department model, you can access the id with just {{ result.id }} or {{ result.pk }}.
I made a booklist where cover image can be uploaded inside Booklist class. For more image I added another class called Bookcover. Now in Views.py how can I send both Booklist and Bookcover's by using BookListView
models.py file is below
from django.db import models
from django.utils import timezone
class Booklist(models.Model):
title = models.CharField(max_length=100)
author = models.CharField(max_length = 100)
cover = models.ImageField(null=True, blank=True, default='default-book.jpg')
description = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
price = models.DecimalField(decimal_places=3, max_digits=100)
def __str__(self):
return self.title
class Bookcover(models.Model):
post = models.ForeignKey(Booklist, default=None, on_delete=models.CASCADE)
covers = models.ImageField(upload_to = 'images/')
def __str__(self):
return self.post.title
here is views.py file
from django.shortcuts import render
from django.views.generic import ListView
from .models import Booklist, Bookcover
def home(request):
return render(request, template_name='home/index.html')
class BookListView(ListView):
model = Booklist
template_name = 'home/index.html'
context_object_name = 'books'
ordering = ['-date_posted']
If you make a ForeignKey, Django automatically will generate a relation in reverse to access - in this case - the related BookCovers for a specific Book. Since you did not specify the related_name=… parameter [Django-doc], the name of this relation is modelname_set, so in this case, bookcover_set.
In the template you can access the book covers of a book with:
{% for book in books %}
{{ book.title }}
{% for cover in book.bookcover_set.all %}
<img src="{{ cover.covers.url }}">
{% endfor %}
{% endfor %}
This will result in an N+1 problem however. You can avoid that by using .prefetch_related(…) [Django-doc]:
class BookListView(ListView):
queryset = Booklist.objects.prefetch_related('bookcover_set')
template_name = 'home/index.html'
context_object_name = 'books'
ordering = ['-date_posted']
I have two applications (blog and category). On the post list template I would like to get the category blog name and description.
I have tried to put the import category model in the blog view, but nothing show up. So I have made two views rendering the same template, but it does not work.
Blog models:
from django.db import models
from django.utils import timezone
from autoslug import AutoSlugField
from category.models import Category
class Post(models.Model):
author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
category = models.ForeignKey(Category, on_delete=models.CASCADE,
default = '')
title = models.CharField(max_length=200)
...
class Meta:
verbose_name = "Post"
verbose_name_plural = "Posts"
ordering = ['created_date']
def publish(self):
self.published_date = timezone.now()
self.save()
def __str__(self):
return self.title
category models:
class Category(models.Model):
name = models.CharField(max_length=200)
slug = AutoSlugField(populate_from='name', default='')
parent = models.ForeignKey('self', blank=True, null=True, related_name='children', on_delete=models.CASCADE)
description = models.TextField(max_length=200)
class Meta:
unique_together = ('slug', 'parent',) # Enforcing that there can not be two
verbose_name_plural = "categories" # categories under a parent with same
# slug
def __str__(self): # __str__ method elaborated later in
full_path = [self.name] # post. use __unicode__ in place of
# __str__ if you are using python 2
k = self.parent
while k is not None:
full_path.append(k.name)
k = k.parent
return ' -> '.join(full_path[::-1])
Blog view:
def post_list(request):
posts = Post.objects.all()
cat_blog = Category.objects.get(pk=1)
context = {
'posts': posts,
'cat_blog': cat_blog
}
return render(request, 'blog/post_list.html', context)
Category view:
def cat_blog(request):
cat_blog = Category.objects.get(pk=1)
return render(request, 'blog/post_list.html', {'cat_blog': cat_blog})
post_list.html:
<div class="section-header text-center">
{% for category in cat_blog %}
<h1>{{ category.name }}</h1>
<p class="tag">{{ category.description }}</p>
{% endfor %}
</div>
<div class="row py-5">
{% for post in posts %}
// This part is fine
{% endfor%}
The post loop is fine. How can't I get the category name and description in my section header?
One URL gives one View gives one template.
You use the View to give context to the template to render.
def post_list(request):
posts = Post.objects.all()
cat_blog = Category.objects.get(pk=1)
context = {
'posts': posts,
'cat_blog': cat_blog
}
return render(request, 'blog/post_list.html', context)
Your url.py file should point to the post_list view.
when i clicked the anchor tag going to the detailed view of my product the url is doubled.
http://127.0.0.1:8000/products/products/t-shirt/
i think it is supposed to be like this:
http://127.0.0.1:8000/products/t-shirt/
List.html
{% for object in object_list %}
{{object.title}}
<br>
{{object.description}}
<br>
{{object.price}}
<br>
<br>
{% endfor %}
models.py
class Product(models.Model):
title = models.CharField(max_length=120)
slug = models.SlugField(blank=True, unique=True)
description = models.TextField()
price = models.DecimalField(decimal_places=2, max_digits=19, default=39.99)
image = models.ImageField(upload_to=upload_image_path, null=True, blank=True)
featured = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
# For url when you click a product
def get_absolute_url(self):
return "products/{slug}/".format(slug=self.slug)
def __str__(self):
return self.title
urls.py
from django.conf.urls import url
from products.views import (product_view,
product_detail_view,
product_featured_view,
)
urlpatterns = [
url(r'products/$', product_view),
url(r'products/(?P<slug>[\w-]+)/$', product_detail_view),
url(r'featured/$', product_featured_view),
]
view.py
from django.shortcuts import render, get_object_or_404, Http404
from .models import Product
def product_view(request):
queryset = Product.objects.all()
context = {
'object_list': queryset,
# 'featured': fqueryset
}
return render(request, 'products/list.html', context)
def product_detail_view(request, slug=None, *args, **kwargs):
try:
instance = get_object_or_404(Product, slug=slug)
except Product.DoesNotExist:
raise Http404("Not Found..")
except Product.MultipleObjectsReturned:
queryset = Product.objects.filter(slug=slug)
instance = queryset.first()
context = {
'object': instance
}
return render(request, 'products/detail.html', context)
def product_featured_view(request):
queryset = Product.objects.filter(featured=True)
context = {
'object_list': queryset
}
return render(request, 'products/featured-list.html', context)
You need to declare your Product.get_absolute_url differently:
def get_absolute_url(self):
return "/products/{slug}/".format(slug=self.slug)
I would also suggest you declare it via reverse as it says here get_abosolute_url.
I'm trying to return all posts associated with a tag using Django. I have searched for a solution but can't find one. I tried to code something but it didn't work. Heres my code
models.py
class Tag(models.Model):
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=200, unique=True)
timestamp = models.DateTimeField(auto_now=False, auto_now_add=True)
updated = models.DateTimeField(auto_now=True, auto_now_add=False)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("posts:tag_index", kwargs={"slug": self.slug})
class Meta:
ordering = ["-timestamp"]
class Post(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, default=1)
slug = models.SlugField(unique=True)
title = models.CharField(max_length=120)
image = models.ImageField(upload_to=upload_location, null=True, blank=True,
width_field="width_field",
height_field="height_field")
height_field = models.IntegerField(default=0)
width_field = models.IntegerField(default=0)
content = models.TextField()
draft = models.BooleanField(default=False)
publish = models.DateField(auto_now=False, auto_now_add=False)
timestamp = models.DateTimeField(auto_now=False, auto_now_add=True)
updated = models.DateTimeField(auto_now=True, auto_now_add=False)
tags = models.ManyToManyField(Tag)
objects = PostManager()
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("posts:detail", kwargs={"slug": self.slug})
class Meta:
ordering = ["-timestamp"]
posts/urls.py
from .views import post_list, post_create, post_detail, post_update, post_delete, sewp, tag_detail
urlpatterns = [
url(r'^$', post_list, name='list'),
url(r'^tag/(?P<slug>[\w-]+)/$', tag_detail, name="tag_index"),
url(r'^create/$', post_create, name='create'),
url(r'^sewp$', sewp, name='sewp'),
url(r'^(?P<slug>[\w-]+)/$', post_detail, name='detail'),
url(r'^(?P<slug>[\w-]+)/edit/$', post_update, name='update'),
url(r'^(?P<id>\d+)/delete/$', post_delete, name='delete'),
]
views.py
def tag_detail(request, slug=None):
query = slug
queryset_list = Post.objects.active()
tags_list = queryset_list.filter(tags__icontains=query).distinct()
instance = get_object_or_404(Tag, slug=slug)
context = {
"instance": instance,
"tags_list": tags_list
}
return render(request, "posts/tag_index.html", context)
tag_index.html
{% extends 'posts/base.html' %}
{% block content %}
{{ instance }}
{{ tags_list }}
{% endblock content %}
I just want to return all the tags and paginate it.
and can I modify the following code to paginate my results :
paginator = Paginator(queryset_list, 2) # Show 25 contacts per page
page_request_var = "page"
page = request.GET.get(page_request_var)
try:
queryset = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
queryset = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
queryset = paginator.page(paginator.num_pages)
context = {
"queryset": queryset,
"title": "Posts",
"page_request_var": page_request_var,
"today": today,
"queryset_list": queryset_list,
"paginator": paginator,
}
any guidance or help on this will be appreciated
If you want to find all Posts associated with a tag, simply use:
posts = Post.objects.filter(tag__title = query)
This will return all posts with the tag specified by the query string.
Read more about making queries here: https://docs.djangoproject.com/en/1.9/topics/db/queries/
I would use a generic ListView like so:
from django.views.generic.list import ListView
from django.shortcuts import get_object_or_404
class TagView(ListView):
template_name = 'posts/tag_index.html'
def get_queryset(self):
""" get the Tag object or return 404 """
self.tag = get_object_or_404(Tag, slug=self.kwargs['slug'])
return Post.objects.filter(tag=self.tag)
def get_context_data(self, **kwargs):
""" add a posts variable to context to use in template """
context = super(TagView, self).get_context_data(**kwargs)
context['posts'] = Post.objects.filter(tag=self.tag)
This is the syntax based on views.py structure
views.py:
def tag_index(request, slug=None):
instance = get_object_or_404(Tag, slug=slug)
ins = instance.post_set.all()
context = {
"instance": ins,
}
return render(request, "posts/tag_list.html", context)
then in the tags_list.html
{% for i in instance %}
{{ i.title }}
{{ i.content }}
{% endfor %}
hope this helps somebody