Python: Making post.file.url unique for image and video files - python

Ive been working on a social media website where you can upload images and videos and follow other users.
I managed to upload and display uploaded files to the website.
I used FileField to load the image and video files, but when I implement it in my Template it shows both spaces, because there both using the same source url {{ source.file.url }}
models.py
class Post(models.Model):
title = models.CharField(max_length=150)
file = models.FileField(upload_to='uploads/%Y-%m-%d')
feeds.html
{% if post.file.url %}
<video class="video-context" width="500px" height="500px" controls>
<source src="{{ post.file.url }}" type="video/mp4">
</video>
{% endif %}
{% if post.file.url %}
<img class="image-context" src="{{ post.file.url }}" type="image/jpg" type="image/jpeg">
{% endif %}
heres a sreenshot empty video player over img
I tried the if endswith form:
{% if file.endswith .mp4 %}
<video class="video-context" width="500px" height="500px" controls>
<source src="{{ post.file.url }}" type="video/mp4">
</video>
{% endif %}
{% if file.endswith .jpg/jpeg %}
<img class="image-context" src="{{ post.file.url }}">
{% endif %}
But it didn't work.
How can I just display the file thats uploaded. How can I make the {{ post.file.url }} unique for image and video, so its easier to difference?
How is it possible to difference the upload types, but still using FileField?

Django templates filter "endswith" doesn't give you the extension of the file in your filefield. Instead, it gives the last character of an object, so in your case, it will be returning 4 if the file is a video type or it will return g if file is an image.
You want to get the extension of the uploaded and unfortunately, there is no filter for that in Django templates.
You need to create a function in your models that will return your file-type/extension.
Models.py
import os
class Post(models.Model):
title = models.CharField(max_length=150)
file = models.FileField(upload_to='uploads/%Y-%m-%d')
def extension(self):
title, extension = os.path.splitext(self.file.name)
return extension
Then in your templates, you can get the extension through this code...
{% for post in posts %}
{% if post.extension == '.mp4'%}
<video class="video-context" width="500px" height="500px" controls>
<source src="{{ post.file.url }}" type="video/mp4">
</video>
{% elif post.extension == '.jpg' or post.extension == '.jpeg' %}
<img class="image-context" src="{{ post.file.url }}">
{% endif %}
{% endfor %}
You can have all sorts of methods on a model to make your life and project easy.

Related

Django template isn't displaying some model object attributes on the page but will display others

I'm following a tutorial on Real Python to create a very simple portfolio website.
https://realpython.com/get-started-with-django-1/
I've created a Project model:
from django.db import models
class Project(models.Model):
title = models.CharField(max_length=100)
description = models.TextField()
technology = models.CharField(max_length=20)
image = models.FilePathField(path="/img")
I've added a number of different objects/projects to this model in the shell and saved them. Here is the HTML for the web page I'm displaying them on:
{% extends "base.html" %}
{% load static %}
{% block page_content %}
<h1>Projects</h1>
<div class="row">
{% for project in projects %}
<div class="col-md-4">
<div class="card mb-2">
<img class="card-img-top" src="{% static project.image %}">
<div class="card-body">
<h5 class="card-title">{{ project.title }}</h5>
<p class="card-text">{{ project.description }}</p>
<a href="{% url 'project_detail' project.pk %}" class="btn-primary">
Read More
</a>
</div>
</div>
</div>
{% endfor %}
</div>
{% endblock %}
As you can see, I'm displaying them on cards that are added using a for loop that iterates every time a new object is created. On this page, the project title, description and read more button are displaying correctly but for some reason the image is not. I have the images placed in a /static/img folder in the same directory as the app 'projects'. And I've tried re-entering the object data, using PNGs, JPEGs etc. but none of these seem to get the images to display correctly.
Next, the 'in detail' page is loaded when the read more button is clicked. Here is the HTML for that:
{% extends "base.html" %}
{% load static %}
{% block page_content %}
<h1>{{ project.title }}</h1>
<div class="row">
<div class="col-md-8">
<img src="{% static project.image %}" alt="" width="100%">
</div>
<div class="col-md-4">
<h5>About the project:</h5>
<p>{{ project.description }}</p>
<br>
<h5>Technology used:</h5>
<p>{{ project.technology }}</p>
</div>
</div>
{% endblock %}
On this page, not only does the image not load, but the project title, description and technology used don't display either. Only a blank space where the image should be and the h5 text shown above is displayed.
I've been following the tutorial as exact as I can and only making small aesthetic changes here and there. I've been through the source code on github and compared my code directly to the authors code and the core components all seem to be exactly the same. Am I missing something?
ADDITIONAL INFO
settings.py static files:
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.1/howto/static-files/
STATIC_URL = 'static/img/'
views.py for the 'projects' app:
from django.shortcuts import render
from projects.models import Project
def project_index(request):
projects = Project.objects.all()
context = {
'projects': projects
}
return render(request, 'project_index.html', context)
def project_detail(request, pk):
projects = Project.objects.get(pk=pk)
context = {
'projects': projects
}
return render(request, 'project_detail.html', context)

How can I loop through dynamic URLs in Django 4?

The problem:
I recently published a site on Python Anywhere and had to go through the tedious process of changing all of the page URLs I had set through my SQLite database. All of the URLs were broken since the root had changed from the local port to "username.pythonanywhere.com".
I had no problem doing this, but I realized that in order to do local development I would need to change the URLs in the database back to their local port paths. This is obviously why we use dynamic URLs. However, the URLs that were hard coded were like that because I was using a for loop on the rendered html page to loop through those static URLs in my database.
My question is, how can I use dynamic URLs {% url app:template %} in a for loop? Ideally, I would like to have a field in my database that contains the app:template information such that I can loop through all the projects in my database and link them dynamically by grabbing the info from that field.
I have tried creating a new CharField in models.py with a string value for {% url app:template %}, hoping that it would work with the templating language of href="{{ project.href_str}}", but this doesn't seem to work. I have tried this method in various combinations of field string values and templating language values. I also tried this method of using the templating language as a string by adding a dictionary to my views.py return statement, with the difference of calling the keys in href="{{ project_urls.appname }}". No luck here either.
Just for the record, I have tried the dynamic URLs that I want outside of loops and they work perfectly, so I don't think this is a problem with the url mapping itself.
Here's the HTML:
In my database, project.href_str has a value of {% url 'calculator:calculator' %}
{% for project in projects %}
<div class="col-lg-3 col-md-6">
{% if project.href_str %}
<a href="{{ project.href_str }}" target="_blank">
<img src="{{ project.image.url }}" class="img-fluid mb-2" style="">
</a>
{% else %}
<img src="{{ project.image.url }}" class="img-fluid mb-2" width="500" height="500">
{% endif %}
<h3 class="">{{ project.title }}</h3>
<p>{{ project.description }}</p>
</div>
{% endfor %}
Answering my own question. All I needed to do was reference the model field without any templating language.
<a href="{% url project.href_str %}" target="_blank"> where project.href_str is a CharField works perfectly fine. My problem was assuming it needed {{}} or something extra.
{% for project in projects %}
<div class="col-lg-3 col-md-6">
{% if project.href %}
<a href="{% url project.href_str %}" target="_blank">
<img src="{{ project.image.url }}" class="img-fluid mb-2" style="">
</a>
{% else %}
<img src="{{ project.image.url }}" class="img-fluid mb-2" width="500" height="500">
{% endif %}
<h3 class="">{{ project.title }}</h3>
<p>{{ project.description }}</p>
</div>
{% endfor %}

How to use easy-thumbnails with static in template?

I wonder how (if it is possible) load thumbnail for static files with easy-thumbnails package.
I tried:
<img src="{% thumbnail 'img/V.png' 50x0 %}" />
<img src="{% thumbnail static 'img/V.png' 50x50 %}" />
<img src="{% static thumbnail 'img/V.png' 50x50 %}" />
but nothing works.
The registered tag filters for easy-thumbnail package are not implemented in a way to render images from the static directory directly. Rather it expects an instance of Image/FileField model (Doc Reference). But you can implement your own filter, redirect the url to static directory and use it based on your needs.
Here, you can adopt one of the following strategies as well.
{% load static thumbnail %}
{% thumbnail image 50x50 crop="center" as thumb %}
{% if thumb %}
<img src="{{ STATIC_URL }}{{ thumb.url }}" width="{{ thumb.width }}" height="{{ thumb.height }}" alt="" />
{% else %}
<img src="{{ STATIC_URL }}img/V.png" alt=""/>
{% endif %}
or
{% load static thumbnail %}
{% thumbnail object.image|default:'{{ STATIC_URL }}img/V.png' 50x50 %}
or by using a custom tag filter to redirect the url of the image instance, if you use S3 bucket instance for static files.
settings.py
S3_ROOT_PATH = "<define your S3 hosting path>"
teamplatetags/s3static
from settings import STATIC_URL, S3_ROOT_PATH
from django import template
register = template.Library()
#register.filter
def s3_static_thumb(image_instance=None):
return "{s3_root_path}{static_path}{image_url}".format(s3_root_path=S3_ROOT_PATH, static_path=STATIC_URL, image_url=getattr(image_instance, "url")) if image_instance and hasattr(image_instance, "url") else None
finally, use that in your template:
{% load static thumbnail s3static %}
{% with image|s3_static_thumb as im_url %}
{% thumbnail image "720x306" crop="center" %}
{% if im %}
<img src="{{ im_url }}" width="{{ image.width }}" height="{{ image.height }}" alt=""/>
{% else %}
<img src="{{ STATIC_URL }}img/V.png" sizes="50x50" alt=""/>
{% endif %}
{% endwith %}

If else code not working in layout.html django

I am trying to implement blog app with django.In home page there will be list of post."post.author.profile.image" is a path to load image from database.If
"post.author.profile.image" is None i need to load an alternative image and if it exist it should load the image from database.So i tried the following code:
def homepage(request):
post= Post.objects.all().order_by('-date')
return render(request,'layout.html',{'posts':post})
layout.html
{% for post in posts %}
<div class="list">
<div class="con">
{% if "post.author.profile.image.url" is None %}
<img src="{% static 'images/b.png' %}" class='logo3'/>
{% else %}
<img src="{{ post.author.profile.image.url }}" class='logo3'/>
{% endif %}
</div>
</div>
{% endfor %}
After running the server if i click on inspect the path in src of image tag is media/None.The code under if is not even running.Whats problem in my code?
How about checking if the image exists?
{% if post.author.profile.image %}
<img src="{{ post.author.profile.image.url }}" class='logo3'/>
{% else %}
<img src="{% static 'images/b.png' %}" class='logo3'/>
{% endif %}
Try this
{% if post.author.profile.image.url %}
<img src="{{ post.author.profile.image.url }}" class='logo3'/>
{% else %}
<img src="{% static 'images/b.png' %}" class='logo3'/>
{% endif %}
Here
{% if "post.author.profile.image.url" is None %}
you're testing if the literal string "post.author.profile.image.url" is None - which it's garanteed to be false, since a literal string is never None.
You want the variable itself:
{% if post.author.profile.image.url is None %}
{% if post.author.profile.image == 'null' %}
<img src="{% static 'images\b.jpg' %}" class="logo3">
{% else %}
<img src="{{post.author.profile.image.url}}" class="logo3">
{% endif %}
I still wonder how this code worked .I tried this before but at that time it was not working may be i would had done some other mistake.But this code is working.

Django: How can you index images from an object_list in a django template

So basically I wanted to know how you can index images in a django template using a for loop. The idea is to create a slide show using the first three images that you user has adds to the model
model.py
class Product(models.Model):
Name=models.CharField(max_length=120,null=True,blank=True)
Category=models.CharField(max_length=80,null=True,blank=True)
Image=models.ImageField(null=True,upload_to='Image')
Description=models.TextField(null=True,blank=True)
Price=models.DecimalField(default=0.00,max_digits=10,decimal_places=2)
Delivery_date=models.DateTimeField(null=True,blank=True)
Delivered=models.BooleanField(default=False)
This is the template but the obj.Image.url tag is incomplete as I want only the first three items and not in a loop but listed out
{% for obj in object_list %}
{% if obj.Image %}
<ul class="pgwSlider">
<li><img src="{{ obj.Image.url }}"></li>
<li>
<img src="">
<span>Shanghai, China</span>
</li>
</ul>
{% endif %}
{% endfor %}
If you simply want just 3 images (maybe it's newest, right), you just deliver your own images context from view to template.
Maybe you're using ListView, then you have to use get_context_data to pass other context data.
this is simple usage for get_context_data. If you want more info, you can check django official documents for simple mixins (Official docs are really helpful!)
Your View example
...
def get_context_data(self, **kwargs):
context = super(YourListView).get_context_data(**kwargs)
context['top_three_images'] = [
product.Image.url
for product in Product.objects.exclude(Image=None)[:3]
]
return context
You can use your own code instead of list comprehension.
Then You can simply use top_three_images in template.
Your Template
{% for image_url in top_three_images %}
<img src="{{ image_url}}" alt="">
{% endfor %}
p.s. I recommend you to use your model field starting with lower_case (i.e. name, category, image ...)
Update
You want to show just first three images inside the loop, right?
If I understand correctly, I think foorloop.coutner maybe helps.
In html, you can use {% if forloop.counter < 4 %} (forloop starts with 1)
{% for obj in object_list %}
{% if forloop.counter < 4 %}
<ul class="pgwSlider">
<li><img src="{{ obj.Image.url }}"></li>
<li>
<img src="">
<span>Shanghai, China</span>
</li>
</ul>
{% endif %}
{% endfor %}
Hoping helpful.
ok i solved this with the help of template tag.Basically i created
from django import template
from Products.models import Product
register=template.Library()
#register.filter
def id_check(value,arg):
arg=arg+value
context=Product.objects.get(id=arg)
return context.Image.url
and ran only one loop in the template
{% for obj in object_list %}
{% if forloop.first %}
<ul class="pgwSlider">
<li><img src="{{ obj.id|id_check:0}}" alt="Montral, QC, Canada" data-large-src="{{ obj.id|id_check:1}}"></li>
<li><img src="{{ obj.id|id_check:1}}" alt="Canada" data-large-src="{{ obj.id|id_check:2}}" ></li>
<li><img src="{{obj.id|id_check:2}}" alt="Montral, QC, Canada" data-large-src="{{ obj.id|id_check:10}}"></li>
<li><img src="{{ obj.id|id_check:3}}" alt="Canada" data-large-src="{{ obj.id|id_check:7}}"></li>
</ul>
{% endif %}
{% endfor %}

Categories