how to display foreignkey image in django - python

Here is the problem, I'm a bit lost with foreignkey, i've seen a lot of post and i don't understand everything.
I have a item table:
class Item(models.Model):
title = models.CharField(max_length=150)
slug = models.SlugField(max_length=100)
price = models.IntegerField()
stock = models.IntegerField()
description = models.TextField()
image = models.ImageField(upload_to=item_file_name)
There is an image wich is the principal. On my index when I list all my item I want to see the image of each item. But when I click on the item I want to see all of the image of this item (in another view). So I've done this.
class ImageOfItem(models.Model):
picture = models.ImageField(upload_to=item_file_name_for_image)
item = models.ForeignKey('Item')
I don't know if it's good but it's working. I can add an item with a picture on the admin panel. And then I can add an image and attach it to the item.(it works, the best way would be to be able to upload all the image when creating the item but I prefer to start easy).
So know everything is save as I want. But I don't know how to display all the images.
My view looks like this:
def view_item(request, id, slug):
item = get_object_or_404(Item, id=id)
return render(request, 'ecommerce/view_item.html', locals())
I don't know if I have to get images too or if django already done it. and there is no var_dump so no way to know if it's in my variable item
my template:
{{item.title}}
{{item.description}}<br>
{{item.price}}<br>
{{item.stock}}<br>
<img src="{{ item.image.url }}"><br> //principal image it works !!
{% for img in item.ImageOfItem %}
<img src="{{ img.picture.url }}"><br> //**all the image I want to display too (but don't know how)**
{% endfor %}
all the image I want to display too (but don't know how)

You should follow relationship backward from Item to ImageOfItem:
{% for img in item.imageofitem_set.all %}
<img src="{{ img.picture.url }}"><br>
{% endfor %}

Related

Django - Parent imageField url isnt showing on template

This is my model structure.
Institution
- name
- logo
- ....
Course
- Owner ( foriegnKey with Institution )
- name
- terms
- .....
So now, am just calling data's like.
courses = Course.objects.filter(name__icontains=query).values('id','name','terms','owner__name', 'owner__logo')
And trying to display the owner__logo as {{data.owner__logo.url}}. But its not working, as the img src shows (unknown). But when this Institution logo thing works on some other view when i directly call it. but when i call via relationship its not working.
If i use {{data.owner__logo}} then it just passes the url without the full path. How to make this work, please help !
An approach that worked for me after I've experimented is...
# Use the FK object id (owner_id) since you're dealing with a FK.
courses = Course.objects.filter(name__icontains=query).values('id','name','terms','owner_id')
If you should print the courses dictionary you'll see the fields it contains for each course. In this case, you'll see the FK with the id listed for that object. Example:
{'id': 10, 'owner_id': 7, 'name': 'Random', 'terms': 'Anything', ...}
What I did from here since the courses object is a dictionary, I've added a new key with with the value being the logo url.
for course in courses:
# First is to get the owner object with the course['owner_id']
owner = Institution.objects.get(id=course['owner_id'])
# From the owner object, you have access to the logo and it's URL
# Creating a new key called 'logo_url' and assigning the owner logo URL to it
course['logo_url'] = owner.logo.url
# Add the courses dictionary to the context variable
context['courses'] = courses
Then within your template, you can access the logo_url for each course.
{% for course in courses %}
<img src="{{ course.logo_url }}"/>
{% endfor %}
OPTION #2: A MORE EFFICIENT WAY
The next option here is to use a template filter to get the Institution object's logo url in just one go while you loop over the items in the template.
In your custom_tags.py file:
from django import template
from django.shortcuts import get_object_or_404
register = template.Library()
#register.filter
def get_logo_url(bypass, owner_id):
# owner = Institution.objects.get(id=owner_id)
# or
owner = get_object_or_404(Institution, id=owner_id) # Recommended
if owner:
url = owner.logo.url
else:
url = ""
return url
In your template and for loop.
{% load custom_tags %} # Must do to be able to use the custom filter
{% for course in courses %}
{% with logo_url=""|get_logo_url:course.owner_id %}
<img src="{{ logo_url }}" />
{% endwith %}
{% endfor %}
If you're not familiar with django custom tags and filters, you can see the doc here.

Django: best way to handle foreign key requests in template pages

Suppose you are making a site to simply list your products.
You want to upload an unspecified number of pictures for your each of your products. So you, following Django's many-to-one documentation, make two models:
# files stored under my_app/static/my_app/product_images/product_<id>/<img_name>
def product_img_dir_path(instance, filename):
return 'my_app/static/my_app/product_images/product_{0}/{1}'.format(instance.product.id, filename)
class Product(models.Model):
name = models.CharField ...
... # other attributes of the product, e.g. price, etc
class ProductImage(models.Model):
product = models.ForeignKey("Product", on_delete=models.CASCADE)
image = models.ImageField(upload_to=product_img_dir_path)
Now if I want all of the images for say product 1, I can retrieve them using:
ProductImages.objects.filter(product__pk=1)
My question starts here.
Suppose you want an index page which just shows the listings for all of your products and for simplicity, the first image associated with each product.
You make a template page with
{% for product in product list %}
<div class="product-listing" style="display:inline">
<!-- image for product goes here -->
<!-- brief description goes here -->
</div>
{% endfor %}
where product_list was passed in your context:
# inside /my_app/views.py
def index(request):
...
context = {"product_list": Product.objects.all()}
...
Question: what is the best way to also have access to the images for displaying the images in the template page?
Currently I thought constructing a parallel image list would suffice:
# inside /my_app/views.py
def index(request):
...
product_list = Product.objects.all()
image_list = [product.productimage_set.all()[0] for product in product_list]
context = {"product_list": product_list, "image_list": image_list}
...
and then somehow using the forloop counter to get the corresponding image for the product.
e.g.
{% for product in product list %}
<div class="product-listing" style="display:inline">
<img src="{{ image_list[<forloop counter>].image.url }}" />
<!-- brief description goes here -->
</div>
{% endfor %}
Is there a better way to do this?
As long as you can access product.productimage_set, you can try to iterate it in your template and do not pass it as a view context.
In your Django template:
{% for product in product_list %}
<div class="product-listing" style="display:inline">
{% for product_image in product.productimage_set.all %}
<img src="{{ product_image.image.url }}" />
<!-- brief description goes here -->
{% endfor %}
</div>
{% endfor %}
I think that it will be easier for you to solve this if you simplify your design by moving the images to your Product model.
If you want to save the path to an image it will be easier to use CharField, but if you want to save many paths why not using JSONField?
My suggestion look like this:
class Product(models.Model):
name = models.CharField(null=True, blank=True)
main_image = models.CharField(null=True, blank=True) # Optional
images = JSONField(null=True, blank=True)

How to add Python data to HTML table

I need to have following table format in HTML:
My question is, how I should organize my Python data correctly so that I can implement this following table format in a clean, Pythonic way. All images belong to the certain version, thus it's important that image is in the right column (order matters). And some versions don't have all (or any) images so in that case, I'll check if "image == None" and show "?" etc. instead of the image. Thus, also 'empty' slots should be saved to data.
Note: I'm doing this with Django and I use Django templates to render this. Ideally, I could do something like following in the template:
<table>
<thead>
<tr>
{% for version in data.versions %}
<th>{{ version }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for image in data.images %}
<tr>
{% for file in image.files %}
{% if file == None %}
<td>No image</td>
{% else %}
<td>{{ file }}</td>
{% endif %}
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
Update: the problem is really how to organize data correctly in the backend. I need to manually initialize a list of versions (Version1, Version2, etc.) I want to put to data and create columns for those. Ordering is important so I need to keep that. Then I'll search for certain Objects which have X amount of images, which all have a certain version. Then I need to loop over those objects (for object in objects) and loop over images of the certain object (for image in object.images) and I should append each image to the column of certain version (add to column where "key" etc. == image.version). If there is no image for certain column, then value should be "None" etc.
I could implement this with list of lists for example:
data = [
['Version1', 'Version2', etc.],
['image',None, etc.],
['image', 'image', etc.],
etc.
]
But I'm pretty sure there is a better way to implement that in Python. So any better suggestions are very welcome.
Update 2: Django models could be like following:
class Version(models.Model):
name = models.CharField(max_length=255)
class Image(models.Model):
file = models.ImageField(upload_to='images')
version = models.ForeignKey(Version)
class Object(models.Model):
images = models.ManyToManyField(Image)
Something like this:
data_versions = { v1 : [img1, img2 ...], v2: [img1, ....]}
There is a better way.
First create a Model (database table) for your data and store everything there. You will have more power in representation of your data that way.
Models.py
class VersionImage(models.Model):
version_number = models.IntegerField()
image_1 = models.ImageField()
image_2 = models.ImageField()
image_3 = models.ImageField()
(I'm making a lot of assumptions on what your data looks like, so might want to change these based on your needs)
A better option (if you're going to have an array of images) would be to store all Images in one model, and make a M2M to your version table:
class ImageModel(models.Model):
image = models.ImageField()
class VersionModel(models.Model):
version_number = models.IntegerField()
image = models.ManyToManyField(ImageModel)
Then you can put the logic you want on the "Form/View" before sending it to your HTML template.
When working with Django, try to put everything on the backend and use HTML just for rendering the data that is already sorted and ready to present.
Let me know if you want me to elaborate on any of the above.

Access foreign key image in template

I have the following models:
class Car(models.Model):
# some fields
class CarPhotos(models.Model):
image = models.ImageField(upload_to='somewhere')
car = models.ForeignKey(Car)
in views.py:
def car_list(request):
cars = Car.objects.all()
return render(request, 'borsa/car_list.html', {'cars': cars})
in car_list.html:
{% for car in cars %}
<a href="car/{{ car.pk }}/view/">
<img class="media-object tmbpic" src="{{ car.carphotos_set.all.0.image.url }}" alt="kola">
</a>
The first method I've used was to use inline formsets but I had no clue how to access the images. Can you please point me in the right direction of how to access images according to Car objects ? I mean every Car must have a couple of images and I need to display only the first one in list view, but then I need to display all of them in Detail view.
To display all of them, you need to do something like:
{% for car in cars %}
{% for photo in car.carphotos_set.all %}
<img src="{{ photo.image.url }}">
{% endfor %}
{% endfor %}
So loop through the cars, then nest-loop through the images per car.

Flask SQLalchemy - many to many - show photo with all tags (or blog with all posts etc)

I am new to Flask and SQLalchemy. Want to have web page with individual photo that shows all tags assigned to that photo.
I have SQLalchemy working fine with MYSQL db. Nicely retrieves records etc.
I need help with flask/SQLalchemy work flow:
model -> view (input from url eg view / photo id) -> template -> web page
The models are as follows:
class Photos(db.Model):
id = db.Column(db.Integer, primary_key=True)
filename = db.Column(db.String(100))
tags = db.relationship(
'Tags',
secondary=photo_tags,
backref='photos')
class Tags(db.Model):
id = db.Column(db.Integer, primary_key=True)
tagname = db.Column(db.String(100))
photo_tags = db.Table('photo_tags',
db.Column('tag_id', db.Integer, db.ForeignKey('tags.id')),
db.Column('photo_id', db.Integer, db.ForeignKey('photos.id'))
)
My view is as follows:
#app.route('/phototags/<int:id>')
##login_required
def phototags(id=None):
photo_tags = Tags.query.filter(Tags.photos).filter(id == id).all()
return render_template(
'phototags.html',
title='PhotoTags',
message='Your application description page.',
photo_tags = photo_tags
)
My template is as follows:
{% extends "layout.html" %}
{% block content %}
<h2>{{ title }}.</h2>
<h3>{{ message }}</h3>
{% for phototag in photo_tags %}
<div style="float:left; class=" img-responsive">
<p>photo</p>
<p></p>tag</p>
<img src="static/photos/{{ phototag.id }}" width="100" height="100">
</div>
{% endfor %}
{% endblock %}
I am pretty sure the models and association table/model are setup properly.
The template is not perfect, as it currently appears to show tag ids for photo ids. I have tried to do 'phototag.photo_id' or 'phototag.filename' but doesn't come out. Obviously view query is not putting that through.
So the view is what i need help with. Is the query correct? and is it getting url passed parameter for photo_id correctly?
My test data is simple. I have a single Photo record with photos.id = 1
This has 2 related Phototags records: phototags.id = 1 (tag.id = 1), phototags.id = 2 (tag.id = 2)
When I pass url http://localhost:5555/phototags/1 my view query passes tag ids, but changing the passed parameter always gets the same tag ids eg phototags/2 also gets the same two tags. So query is obviously not correct.
I have looked at scores of examples and they all subtly different than what I want. None of the examples/tutorials/SO questions/answers i have seen show how the model, view and template work together to get what I want. They are either:
getting opposite eg equivalent of photos by tag (want tags by photo)
are just query that gets the tags by photo (i don't even think i am getting that)
have another SQLalchemy notation that includes 'sessions' or 'base' instead of 'db.model'
What I want as output is a photo id so i can show photo and its name etc and also show a list of tags associated with that photo eg as a comma separated list.
I am stumped to find a demo/example/tutorial/github project that walks me through what i need for workflow.
Can anyone show me example of view that can get photo id from url parameter and then query my models to get the associated tags?
It seems more appropriate to query a photo instead of photo_tags from what you describe about your use case.
With the view function
#app.route('/phototags/<int:id>')
def phototags(id=None):
photo = Photo.query.get(id)
return render_template(
'phototags.html',
title='PhotoTags',
message='Your application description page.',
photo = photo
)
you can then display the photo and iterate its tags using the 'tags' relationship in the html template:
{% extends "layout.html" %}
{% block content %}
<h2>{{ title }}.</h2>
<h3>{{ message }}</h3>
<img src="static/photos/{{ photo.id }}" width="100" height="100">
{% for phototag in photo.tags %}
<div style="float:left; class=" img-responsive">
<p>photo</p>
<p></p>tag</p>
</div>
{% endfor %}
{% endblock %}
Note that I used the get function in the query for the Photo. It's basically the same as
Photo.query.filter(id == id).first()
Renaming the view function and the template from phototags to photo would also make sense.
If you wanted to display all images for a tag you have to reverse the logic, querying for a tag and iterating over the photos. Should be possible, because you defined a backref.

Categories

Resources