I'm trying to make a blog website. On the all post page, it renders all the posts from the database. But not all post has its feature image. So, I'm trying to hide those image sections that don't have any featured images.
Here is blog/model.py
class Article(models.Model):
STATUS_CHOICES = (
('draft', 'Draft'),
('published', 'Published'),
)
author = models.ForeignKey(Profile, null=True, blank=True, on_delete=models.SET_NULL)
title = models.CharField(max_length=200)
slug = AutoSlugField(populate_from='title', unique=True, null=False, db_index=True)
excerpt = models.CharField(max_length=60)
featured_image = models.ImageField(upload_to="posts", null=True, blank=True, default="default.jpg")
content = FroalaField()
created = models.DateTimeField(auto_now_add=True)
last_update = models.DateTimeField(auto_now=True)
publish = models.DateTimeField(default=timezone.now)
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft')
Here is blog/view.py
# display all blog posts
def posts(request):
all_posts = Article.published.all()
context = {'all_posts': all_posts}
return render(request, 'blog/posts.html', context)
# Single post
def single_post(request, slug):
post = Article.objects.get(slug=slug)
context = {
'post': post,
}
return render(request, 'blog/single-post.html', context)
Here is blog/url.py
urlpatterns = [
path('', views.posts, name="posts"),
path('post/<slug:slug>/', views.single_post, name="single-post"),
]
Here is post.html
{% for post in all_posts %}
<li class="bg-white px-4 py-6 shadow sm:p-6 sm:rounded-lg">
<article aria-labelledby="question-title-81614">
<a href="{{ post.get_absolute_url }}">
<!-- author details & option menus -->
<div class="flex space-x-3">
<div class="flex-shrink-0">
<!-- author image -->
<img
class="h-10 w-10 rounded-full"
src="{{ post.author.profile.avatar.url }}"
alt=""
/>
</div>
<!-- author name and publish date time -->
<div class="min-w-0 flex-1">
<p class="text-sm font-medium text-gray-900">
Dries Vincent
</p>
<p class="text-sm text-gray-500">
<time datetime="{{ post.publish.date }}"
>{{ post.publish.date }}
</time>
</p>
</div>
</div>
<div class="mt-4 space-y-4">
{# show image if there is a feature image #}
{% if post.featured_image.url %}
<!-- article images -->
<img
class="object-cover w-full h-64 bg-center rounded-lg"
src="{{ post.featured_image.url }}"
alt="{{ post.title }}"
/>
{% endif %}
</div>
<!-- article title -->
<h1
id="question-title-81614"
class="mt-4 text-xl font-medium text-gray-900"
>
{{ post.title }}
</h1>
</a>
</article>
</li>
{% endfor %}
Here is the image for a better understanding
post.html template page
This looks more like a wrong default, if no image is provided you should set it to None/NULL:
class Article(models.Model):
# ⋮
featured_image = models.ImageField(upload_to='posts', null=True, blank=True, default=None)
you can then render it with a condition like:
{% if post.featured_image %}
<!-- article images -->
<img
class="object-cover w-full h-64 bg-center rounded-lg"
src="{{ post.featured_image.url }}"
alt="{{ post.title }}"
/>
{% endif %}
You can set the Articles with a default.jpg to None for example with a query in the Django shell:
Article.objects.filter(
featured_image='default.jpg'
).update(featured_image=None)
While defining your model, null=True and Blank=True also set the default to None.
If you're going to render Alf those that have featured_picture, you'll need to add a little if post.featured_picture, or whatever your image field is named, and you're good to go.
Related
If I open a blog detail, there should be the previous blog and next blog title as a pagination. From Django documentation, I implemented the pagination by page number. But how can I implement the pagination by previous blog and next blog title.
Here is my model.py:
class Post(models.Model):
title = models.CharField(max_length=250, unique=True)
slug = models.SlugField(max_length=250, unique=True, null=True, blank=True)
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name="blog_posts")
cover = models.ImageField(upload_to="Uploaded/")
content = RichTextUploadingField(blank=True, null=True)
sticker = models.CharField(max_length=50, unique=False, null=True, blank=True)
published_at = models.DateTimeField(auto_now_add=True)
updated_on = models.DateTimeField(auto_now=True)
status = models.IntegerField(choices=STATUS, default=0)
tags = models.CharField(max_length=400, null=True, blank=True)
class Meta:
ordering = ['-published_at']
def __str__(self):
return self.title
views.py
class PostDetail(generic.DetailView):
model = Post
template_name = 'blogs/post_detail.html'
post_detail.html
{% extends "blogs/base.html" %}
{% load static %}
{% block post %}
<section class="services">
<dev class="box-container">
<div class="box-lg">
<h3>{{ post.title }}</h3>
<img src="/Images/{{ post.cover }}" >
<hr>
<small>{{ post.published_at }}</small>
<p>{{ post.content | safe }}</p>
</div>
</dev>
</section>
<!-- Pagination Start -->
<div class="center">
</div>
<!-- Pagination Ends -->
{% endblock post %}
Now please help me how to do the prev-next blog titled pagination like the below image!
titled pagination image
One way you can handle this is to use .get_previous_by_Foo and .get_next_by_Foo you can read more here : https://docs.djangoproject.com/en/2.1/ref/models/instances/#django.db.models.Model.get_next_by_FOO
This is just an idea how you can do it.
{% extends "blogs/base.html" %}
{% load static %}
{% block post %}
<section class="services">
<dev class="box-container">
<div class="box-lg">
<h3>{{ post.title }}</h3>
<img src="/Images/{{ post.cover }}" >
<hr>
<small>{{ post.published_at }}</small>
<p>{{ post.content | safe }}</p>
</div>
</dev>
</section>
<!-- Pagination Start -->
<div class="center">
{{ post.get_previous_by_published_at.title }}
</div>
<!-- Pagination Ends -->
<div class="center">
{{ post.get_next_by_published_at.title }}
</div>
{% endblock post %}
as i said this just an idea in real life you have to check that next or previous post exists or maybe that post is the last one a thing like that...
I am having a challenge displaying multiple images users post to one img template element, for one reason if i try fetching images with the default related name it wouldn't show in the template and i wonder what i am doing wrong. Can anyone be of help!
Here is my model for post.
class Post(models.Model):
page = models.ForeignKey(Page, on_delete=models.CASCADE, related_name="page")
username = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE ,related_name="page_user")
description = models.TextField(max_length=500, blank=True)
video = models.FileField(upload_to="PageVideos", blank=True)
pic = models.ImageField(blank=True)
date_posted = models.DateTimeField(auto_now_add=True)
tags = models.CharField(max_length=100, blank=True)
class Mete:
ordering = ['-date_posted']
def __str__(self):
return self.description
class PostImage(models.Model):
#page = models.ForeignKey(Page, on_delete=models.CASCADE, related_name="pg")
post = models.ForeignKey(Post, default=None, on_delete=models.CASCADE)
images= models.ImageField(upload_to="postimages/")
Here is my Detail view
def page_detail(request,id):
post = get_object_or_404(Post, id=id)
photos = PostImage.objects.filter(post=post)
context = {
'post':post,
'photos':photos
}
return render(request, 'page/detail.html',context)
These my Template to display users images
<div class="p-3 border-b dark:border-gray-700">
{{ post.description }}
</div>
<div uk-lightbox>
<div class="grid grid-cols-2 gap-2 p-2">
{% for p in photos.images_set.all %}
<a id="images" href="{{ p.images.url }}" class="col-span-2" >
<img src="{{ p.images.url }}" alt="" class="rounded-md w-full lg:h-76 object-cover">
</a>
<a href="">
<img src="" alt="" class="rounded-md w-full h-full">
</a>
<a href="" class="relative">
<img src="" alt="" class="rounded-md w-full h-full">
<div class="absolute bg-gray-900 bg-opacity-30 flex justify-center items-center text-white rounded-md inset-0 text-2xl"> + see more </div>
</a>
{% endfor %}
</div>
</div>
your photos is a list you dont need reverse m2m (the "images_set") simply change this in html
....
<div class="grid grid-cols-2 gap-2 p-2">
{% for p in photos %}
....
for optimize you can do this
from django.http import Http404
...
def page_detail(request,id):
try:
# with prefetch you do only one sql request
post = Post.objects.select_related('images_set').get(id=id)
expect Post.DoesNotExist as err:
raise Http404(err)
context = {
'post': post,
'photos': post.images_set.all()
}
return render(request, 'page/detail.html',context)
I'm trying to add a delete button for a single comment of current user inside a post. I tried the function below in my views.py , but it comes back as error: Page not found (404)
Request Method: GET
Request URL: http://127.0.0.1:8000/comments/15/delete/
Raised by: feed.views.comment_delete
Any ideas what I'm doing wrong ?
views.py
#login_required
def comment_delete(request, pk):
comment = get_object_or_404(Comments, pk=pk)
if request.user.id == comment.username_id:
Comments.objects.get(pk=pk).delete()
messages.error(request, f'Comment Deleted')
return redirect('post-detail', pk=pk)
models.py
class Post(models.Model):
description = models.TextField(max_length=255)
pic = models.ImageField(upload_to='path/to/img', blank=True)
date_posted = models.DateTimeField(default=timezone.now)
user_name = models.ForeignKey(User, on_delete=models.CASCADE)
tags = models.CharField(max_length=100, blank=True)
def __str__(self):
return self.description
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk': self.pk})
class Comments(models.Model):
post = models.ForeignKey(Post, related_name='details', on_delete=models.CASCADE)
username = models.ForeignKey(User, related_name='details', on_delete=models.CASCADE)
comment = models.CharField(max_length=255)
comment_date = models.DateTimeField(default=timezone.now)
post_detail.html
<h4 class="comment_text">Comments</h4>
<div class="row">
<div class="col-xl-9 col-md-10 m-auto order-xl-2 mb-0 mb-xl-0">
{% if post.details.all %}
<div class="card card-signin my-0">
{% for detail in post.details.all %}
<div class="card-body">
<a href="{{ detail.username.profile.get_absolute_url }}">
<img src="{{ detail.username.profile.image.url }}" class="rounded-circle" width="30" height="30" alt="">
</a>
<a class="text-dark" href="{{ detail.username.profile.get_absolute_url }}"><b>{{ detail.username }}</b></a>
<a class="comment_delete" href="{% url "comment-delete" user.id %}">delete</a>
<br><small>{{ detail.comment_date }}</small><br><br>
<p class="card-text text-dark">{{ detail.comment }}</p>
</div>
<hr class="my-1">
{% endfor %}
</div>
{% else %}
<p>No comments to show!</p>
{% endif %}
</div>
In your template you write {% url "comment-delete" user.id %} when in fact the argument that the view expects is the comments id/pk. Change it to {% url "comment-delete" detail.pk %}
I am developing an ecommerce website with Django. I had Product and Product_images models as below:
class Product(models.Model):
tags = models.ManyToManyField(Tag, related_name='products')
same_product = models.ManyToManyField('self', related_name='same_products', blank=True)
category = models.ForeignKey('Category', on_delete=models.CASCADE, related_name='product_categories')
who_like = models.ManyToManyField(User, related_name='liked_products', blank=True)
title = models.CharField('Title', max_length=100, db_index=True)
slug = models.SlugField('Slug', max_length=110, unique = True)
sku = models.CharField('SKU', max_length=50, db_index=True)
description = models.TextField('Description', null=True, blank=True)
sale_count = models.IntegerField('Sale Count', default=0)
is_new = models.BooleanField('is_new', default=True)
is_featured = models.BooleanField('is_featured', default=False)
is_discount = models.BooleanField('is_discount', default=False)
price = models.DecimalField('Price', max_digits=7, decimal_places=2)
discount_value = models.IntegerField('Discount Value', null=True, blank=True)
def __str__(self):
return self.title
class Product_images(models.Model):
# relations
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='images')
# informations
image = models.ImageField('Image', upload_to='media/product_images')
is_main = models.BooleanField('Main Image', default=False)
is_second_main = models.BooleanField('Second Main Image', default=False)
# moderations
status = models.BooleanField('Status', default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'image'
verbose_name = 'Image'
verbose_name_plural = 'Images'
ordering = ('created_at',)
def __str__(self):
return f'{self.image}'
In my Product_images model I store several images for one Product, in Product_images model I wrote
boolean fields with names is_main and is_second_main. In my template I want to get these images, in my terminal (interactive shell) when I write single_product.images.get(is_main=True).image.url can get image url, but in template I can't get image, but get an error as below:
TemplateSyntaxError at /
Could not parse the remainder: '(is_main=True).image.url' from 'product.images.get(is_main=True).image.url'
Below is my view and template:
def index(request):
products = Product.objects.all()
context = {
'products': products
}
return render(request, 'index/index.html', context)
{% for product in products %}
<div class="front">
<a href="product-page(no-sidebar).html">
<img src="{{ product.images.get(is_main=True).image.url }}" class="img-fluid blur-up lazyload bg-img" alt="">
</a>
</div>
<div class="back">
<a href="product-page(no-sidebar).html">
<img src="{{ product.images.get(is_main=True).image.url }}" class="img-fluid blur-up lazyload bg-img" alt="">
</a>
</div>
{% endfor %}
Please, help me with this problem and properly display these images, thanks in advance.
I already solve this problem, maybe it is not the best way, but work.
{% for product in products %}
<div class="product-box">
<div class="img-wrapper">
<div class="front">
<a href="{% url 'product-detail' product.slug %}">
{% for image in product.images.all %}
{% if image.is_main %}
<img src="{{ image.image.url }}" class="img-fluid blur-up lazyload bg-img" alt="">
{% endif %}
{% endfor %}
</a>
</div>
<div class="back">
<a href="{% url 'product-detail' product.slug %}">
{% for image in product.images.all %}
{% if image.is_second_main %}
<img src="{{ image.image.url }}" class="img-fluid blur-up lazyload bg-img" alt="">
{% endif %}
{% endfor %}
</a>
</div>
{% endfor %}
I'm trying to set up magnific popup on django.
My goal is to have one main picture in the homepage overview gallery view, which when clicked, would open a popup with the related images from the same photoshoot i.e. images with the same ID or PK.
I tried to apply the following approach
but i just cannot get it to work, maybe someone could help me out in this
My models.py
class Item(models.Model):
name = models.CharField(blank=False, max_length=200)
category = models.ForeignKey(Category, blank=True, null=True, on_delete=models.SET_NULL)
order = models.IntegerField(blank=True, null=True)
active = models.BooleanField(blank=True, default=False)
objects = models.Manager()
class Meta:
verbose_name_plural = 'items'
def __str__(self):
return self.name
class ItemImage(models.Model):
image = ProcessedImageField(
blank=True,
null=True,
processors=[ResizeToFit(width=1680, upscale=False)],
format='JPEG',
options={'quality':90})
order = models.IntegerField(blank=True, null=True)
main = models.BooleanField(blank=True, default=False)
cover = models.BooleanField(blank=True, default=False)
item = models.ForeignKey(Item, related_name='items', blank=True, null=True, on_delete=models.SET_NULL)
objects = models.Manager()
class Meta:
verbose_name_plural = 'item images'
Views.py
def portraits(request):
port = ItemImage.objects.filter(item__category__slug='portraits', item__active=True, main=True,).order_by('item__order')
portall = ItemImage.objects.filter(item__category__slug='portraits', item__active=True).order_by('item__order')
context = {
'main_portraits': port,
'all_portraits': portall
}
return render(request, 'gallery/portraits.html', context)
and Template:
{% block content %}
<div class="grid">
{% for pic in main_portraits %}
<div class="item">
<div class="item">
<div class="outer-text">
<div class="text">
{{ pic.item.name }}
<p>Click to view gallery</p>
</div>
</div>
<a><img class="lazy" alt=""
sizes="(min-width:1400px) 1220px
(min-width:1000px) 1000px,
(min-width:500px) 700px,
(min-width:320px) 420px,
280px"
srcset="{{ pic.image_xs.url }} 280w,
{{ pic.image_s.url }} 420w,
{{ pic.image_m.url }} 700w,
{{ pic.image_l.url }} 1000w,
{{ pic.image_xl.url }} 1220w" />
</a> {{ pic.item.pk }}
</div>
<div class="lazy">
{% for p in all_portraits %}
{% endfor %}
</div>
</div>
{% endfor %}
</div>
{% endblock %}
I have set
z.item.pk
just as a test, to see if any of my manipulations result in the pk's to bunch up. For example the first for-loop returns a picture with PK "24", I need for the second for-lop to return only images with the same PK; and so for every image. I think the answer might be connected with _set.all function, just like in the related question above, but I cant seem to get it to work in my case. Feels like I'm missing something here.
current output:
<div class="grid">
<div class="item">
<div class="item">
<div class="outer-text">
<div class="text">
Palagā tītā
<p>Click to view gallery</p>
</div>
</div>
<a><img class="lazy" alt=""
sizes="(min-width:1400px) 1220px
(min-width:1000px) 1000px,
(min-width:500px) 700px,
(min-width:320px) 420px,
280px"
srcset="/media/CACHE/images/IMG_8329_3Vi8mYO_GD621ql/958ba5dbee5efe28fd2f5054b8f819e1.jpg 280w,
/media/CACHE/images/IMG_8329_3Vi8mYO_GD621ql/02d12ca7f0633fee2fc762cf96f7889e.jpg 420w,
/media/CACHE/images/IMG_8329_3Vi8mYO_GD621ql/ba5fa6633e92a288e3b2f47a713d64c2.jpg 700w,
/media/CACHE/images/IMG_8329_3Vi8mYO_GD621ql/fe0d559fef5b02434c43f841005d4961.jpg 1000w,
/media/CACHE/images/IMG_8329_3Vi8mYO_GD621ql/96d0e52dff14d1bc4b60bbec674565db.jpg 1220w" />
</a> 24
</div>
<div class="lazy">
</div>
</div>
You need prefiltered querysets containing the related images for every main image before handing over to the template.
def portraits(request):
ports = ItemImage.objects.filter(item__category__slug='portraits', item__active=True, main=True,).order_by('item__order')
for p in ports:
# You may not need the item__category__slug filter
# if there are only images of the same category
# associated with an item.
# Also, if you want to exclude the main image
# from the set of related images, you need to add the filter
# main=False
p.related_images = ItemImage.objects.filter(item__category__slug='portraits', item__id=p.item.id)
context = {
'main_portraits': ports,
}
return render(request, 'gallery/portraits.html', context)
Then you can loop over main_portraits in the template, and get the related images for each main image in a nested loop:
{% for mainp in main_portraits %}
{% for im in mainp.related_images %}
{# do something with the related images #}
{% endfor %}
{% endfor %}
You can break down the models like this it will make the querying easier.
# models.py
class Item(mdoels.Model):
name = models.CharField(blank=False, max_length=200)
category = models.ForeignKey(Category, blank=True, null=True, on_delete=models.SET_NULL)
...
display_image = models.ProcessedImageField(...)
class ItemImage(models.Model):
item = models.ForeignKey(Item, related_name='images', blank=True, null=True, on_delete=models.SET_NULL)
image = models.ProcessedImageField(...)
...
#views.py
def portraits(request):
items = Item.objects.filter(category__slug='portraits', active=True)
return render(request, 'gallery/portraits.html', context={items: items})
#template
{% for item in items %}
<h1> {{item.name}} </h1>
<img src={{item.display_image}} />
{% for item_image in item.images.all %}
<img src={{item_image.image}} />
{% endfor %}
{% endfor %}