Django foreign key object image in template - python

Ok I know a thousand people asked this but I have looked all over this site to no success(also google) here is my models.py
VENUE_IMAGE_PATH = os.path.join('images', 'venue_profiles/%Y/%m/%d')
class Venue(models.Model):
.....................
name = models.CharField(max_length=100)
address = models.CharField(max_length=100)
city = models.CharField(max_length=100)
...........................
class VenueImage(models.Model):
venue = models.ForeignKey(Venue, related_name="venue")
image = models.ImageField(upload_to=VENUE_IMAGE_PATH, max_length=255)
Here is my views.py
def list(request):
venues = Venue.objects.all()
images=VenueImage.objects.all()
return render_to_response('venues/list.html', {'venues':venues,'images':images},
context_instance = RequestContext(request))
here is my template
{% for v in venues %}
<a href='#'>{{v.name}}</a>
edit
{% if images %}
<img class='venue_image' src='images/venue_profiles/2012/10/25/{{images.url}}'
alt=''>
{% endif %}
{% endfor %}
Now I have tried {{images.images.url}} and {{images.url}}. {{MEDIA_URL}}images/venue_profiles/%Y/%m/%d/{{image.url}}.
I also tried {%for i in images %} {{i.url}} {% endfor %}.
I also tried without that 'images/venue_profiles/2012/10/25' prefix and nothing seems to work.
Can someone please help me see what I am doing wrong.

# In models.py
class Venue(models.Model):
....
name = models.CharField(max_length=100)
....
images = models.ForeignKey(VenueImage)
class VenueImage(models.Model):
image = models.ImageField(upload_to=VENUE_IMAGE_PATH)
# In views.py
def list(request):
venues = Venue.objects.all()
return render(request,
'venues/list.html',
{'venues': venues'})
# In template
{% for venue in venues %}
<a href '#'>{{ venue.name }}</a>
...
{% for image in venue.images %}
<img class='venue_image' src=''{{ image.url }}' alt=''>
{% endfor %}
{% endfor %}

Related

Django add to wishlist

I have to do wishlist, I have done wishlist page, model and html.bBut when I click on the button bellow my post, I'm redirected to wishlist page and post didnt saved in my wishlist.So thats my code:
models.py
class Wishlist(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
wished_item = models.ForeignKey(Posts, on_delete=models.CASCADE)
def __str__(self):
return self.wished_item.title
class Posts(models.Model):
TYPE = Choices(
('private', _('private')),
('business', _('business')),
)
STATUS = Choices(
('active', _('active')),
('deactivated', _('deactivated'))
)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, related_name='posts',
on_delete=models.CASCADE, verbose_name='owner')
phone_number = PhoneNumberField(verbose_name=_('Phone_number'), null=False, blank=False, unique=True)
title = models.CharField(verbose_name=_('Title'), max_length=100)
text = RichTextField(verbose_name=_('Text'))
image = models.ImageField(upload_to='images/%Y/%m/%d/', null=True, blank=True, validators=[file_size])
price = models.DecimalField(verbose_name=_('Price'), decimal_places=2, max_digits=9)
status = models.CharField(choices=STATUS, max_length=50)
created = models.DateTimeField(auto_now=True)
type = models.CharField(choices=TYPE, max_length=50)
def __str__(self):
return self.title
views.py
class WishListView(generic.View):
def get(self, *args, **kwargs):
wish_items = Wishlist.objects.filter(user=self.request.user)
context = {
'wish_items': wish_items
}
return render(self.request, 'wishlist/wishlist.html', context=context)
def addToWishList(request):
if request.method == 'POST':
post_var_id = request.POST.get('object-id')
post_var = Posts.objects.get(id=post_var_id)
print(post_var)
try:
wish_item = Wishlist.objects.get(user=request.user, post=post_var)
if wish_item:
wish_item.save()
except:
Wishlist.objects.create(user=request.user, post=post_var)
finally:
return HttpResponseRedirect(reverse('wishlist'))
wishlist.html
{% extends 'posts/base.html' %}
{% load thumbnail %}
{% block content %}
<div>
{% for item in wish_items %}
{% if item.wished_item.image1 %}
<img src="{{item.wished_item.image.url}}" alt="">
{% endif %}
</div>
<div>
<li>{{item.wished_item.title}}</li>
<li>{{item.wished_item.text}}</li>
<li>{{item.wished_item.price}}</li>
<li>{{item.wished_item.phone_number}}</li>
{% if item.wished_item.image %}
<img src="{% thumbnail item.wished_item.image 200x200 crop %}" alt="" />
<p></p>
{% endif %}
</div>
{% endfor %}
{% endblock %}
urls.py
urlpatterns = [
path("wishlist/", WishListView.as_view(), name='wishlist'),
path("add-to-wishlist", addToWishList, name='add-to-wishlist'),
]
and all posts template with add to wishlist button.
<ul>
{% for object in object_list %}
<li>Owner: {{ object.owner }}</li>
<li>Phone: {{ object.phone_number }}</li>
<li>Title: {{ object.title }}</li>
<li>Text: {{ object.text }}</li>
<li>Type: {{ object.type }}</li>
<li>Price: {{ object.price }}</li>
<li>Date: {{ object.created }}</li>
<p>
{% if object.image %}
<img src="{% thumbnail object.image 200x200 crop %}" alt="" />
{% endif %}
</p>
<form action="{% url 'add-to-wishlist' %}" method="POST">
{%csrf_token%}
<input type="hidden" name="object-id" value="{{object.id}}">
<input type="submit" value="Add to Wishlist">
</form>
<hr/>
Probably problem with posts Id, but I'm not sure in that.
You can use get_or_create instead of the if else statement for if exist or not. And use get_object_or_404 to make code more clear.
from django.shortcuts import get_object_or_404
def addToWishList(request):
if request.method == 'POST':
post_obj = get_object_or_404(Post, pk=request.POST.get('object-id'))
Wishlist.objects.get_or_create(user=request.user, post=post_obj)
return HttpResponseRedirect(reverse('wishlist'))
In your views.py try to replace these lines:
try:
wish_item = Wishlist.objects.get(user=request.user, post=post_var)
if wish_item:
wish_item.save()
except:
Wishlist.objects.create(user=request.user, post=post_var)
with
wish_item, was_created = Wishlist.objects.get_or_create(user=request.user, post=post_var)
# for debugging
if was_created:
print(f"{wish_item} was created")
else:
print(f"{wish_item} already exists")
what is the output?
The code looks OK for me. You might add a trailing / in your urls.py after the path("add-to-wishlist/" ... but I can't spot anything wrong in the first place.

Adding a maximum limit to the number of post using python

I need to limit the number of posts in Django queries. I have tried to add a min and max but nothing seemed to have worked. I have added home.html into the code.
Example: I should only have the 15 most recent posts in my blog. The rest can be seen by clicking on the category button.
Home.html:
{% extends 'base.html' %}
{% block content %}
<h1>Posts</h1>
<ul>
{% for post in object_list %}
<li>{{post.title}}
<style>
a {
text-transform: capitalize;
}
</style>
- {{ post.category }} - <a href="{% url 'show_profile_page' post.author.profile.id %}">{{ post.author.first_name }}
{{ post.author.last_name }}</a> - {{ post.post_date }} <small>
{% if user.is_authenticated %}
{% if user.id == post.author.id %}
- (Edit)
(Delete)
{% elif user.id == 1 %}
- (Edit)
(Delete)
{% endif %}
{% endif %}
</small><br/>
{{ post.snippet }}</li>
{% endfor %}
</ul>
{% endblock %}
view.py:
class HomeView(ListView):
model = Post
template_name = 'home.html'
ordering = ['-id']
def get_context_data(self, *args, **kwargs):
cat_menu = Category.objects.all()
context = super(HomeView, self).get_context_data(*args,**kwargs)
context["cat_menu"] = cat_menu
return context
models.py:
class Post(models.Model):
title = models.CharField(max_length=255)
header_image = models.ImageField(null=True, blank=True, upload_to='images/')
title_tag = models.CharField(max_length=255)
author = models.ForeignKey(User, on_delete=models.CASCADE)
body = RichTextField(blank=True, null=True)
post_date = models.DateField(auto_now_add=True)
category = models.CharField(max_length=255, default='intro')
snippet = models.CharField(max_length=255)
likes = models.ManyToManyField(User, related_name='post_likes')
dislikes = models.ManyToManyField(User, related_name='post_dislikes')
I think you have another template for displaying categorised objects when you click category button. As you said
"I should only have the 15 most recent posts in my blog. The rest can
be seen by clicking on the category button."
In this case you can use a simple hack to display most recent posts from your table.
query all objects in descending order in views
all_objs = Post.objects.all().order_by('-id')
Then use {% if forloop.counter <= 15 %} to display last 15 items only. as follow.
templates
{% for post in object_list %}
{% if forloop.counter <= 15 %}
<h4>{{obj}} #or anything really that is meant to be shown on the home page.</h4>
{% endif %}
{% endfor %}
You can do something like this:
def get_context_data(self, *args, **kwargs):
context = super(HomeView, self).get_context_data(*args,**kwargs)
context["cat_menu"] = Category.objects.all()
context["most_recent_posts"] = Post.objects.filter(author=self.request.user).order_by('-post_date')[:15]
return context
This will get the 15 most recent posts authored by the current user, ordered by the date it was posted.
Then just handle displaying this in home.html for example:
<ul>
{% for p in most_recent_posts %}
<li>{{ p.title }}</li>
{% endfor %}
</ul>
Just limit your query to the latest 15 entries sorted by post_date:
cat_menu = Category.objects.latest("post_date")[:15]
https://docs.djangoproject.com/en/3.2/topics/pagination/
The best way is Django Pagintion.
{% for contact in page_obj %}
{# Each "contact" is a Contact model object. #}
{{ contact.full_name|upper }}<br>
...
{% endfor %}
<div class="pagination">
<span class="step-links">
{% if page_obj.has_previous %}
« first
previous
{% endif %}
<span class="current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
next
last »
{% endif %}
</span>
</div>
from django.core.paginator import Paginator
from django.shortcuts import render
from myapp.models import Contact
def listing(request):
contact_list = Contact.objects.all()
paginator = Paginator(contact_list, 25) # Show 25 contacts per page.
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
return render(request, 'list.html', {'page_obj': page_obj})
you can use Django pagination api . Manage your data through page number. Initially pass 1 and after that page number given by pagination.
paginator = Paginator(yourquerysetdata, 20)
page_num = request.data.get('page')
result = yourSerializerName(paginator.get_page(page_num) many=True).data
try:
page = paginator.page(page_num)
except:
page = paginator.page(1)
count = paginator.num_pages
resultobj = paginator.get_page(page_num)
has_prev = resultobj.has_previous()
has_next = resultobj.has_next()
page_range = resultobj.paginator.page_range.stop - 1
if has_prev:
prev_page_no = resultobj.previous_page_number()
else:
prev_page_no = 0
if has_next:
next_page_no = resultobj.next_page_number()
else:
next_page_no = None
context = dict()
context['page'] = page.number
context['page_no'] = count
It is very simple. You just have to modify the query that you are using to fetch the posts.
In the get_context_data() method, replace cat_menu = Category.objects.all() with cat_menu = Category.objects.all().order_by('-post_date')[:15]. This will limit the number of results to 15 most recent objects.
For more understanding, you can take a look at the official Django docs for Limiting QuerySets.

display contents of manytomany and foreignjey fields in Django

I'm new to Django and I'ma building a basic blog application.
I cant show manytomany field (in tags) and a foreignkey field (comments) in my details page.
models.py
class BlogContent(models.Model):
title = models.CharField(max_length=200)
author = models.CharField(max_length=200)
content = models.TextField()
date_published = models.DateField(auto_now=True)
image = models.ImageField(upload_to='media/')
def __str__(self):
return self.title
class TagName(models.Model):
tag = models.ManyToManyField(BlogContent, null=True)
name = models.CharField(max_length=100, blank=True, null=True)
def __str__(self):
return self.name
class Comment(models.Model):
comt_text = models.TextField()
comments = models.ForeignKey(BlogContent, on_delete=models.CASCADE)
date_published = models.DateField(auto_now=True)
name = models.CharField(max_length=200, blank=True, null=True)
def __str__(self):
return self.name
views.py
def details(request, blogcontent_id):
data_blog = get_object_or_404(BlogContent, pk=blogcontent_id)
data_tag = get_object_or_404(TagName, pk=blogcontent_id)
data_comment = Comment.objects.select_related()
return render(request, 'details.html',
{'data_blog': data_blog, 'data_tag':data_tag, 'data_comment':data_comment})
details.html
{% extends 'base.html' %}
{% block body_base %}
<img class="card-img-top img-responsive" src={{ data_blog.image.url }} alt="Card image cap">
<h2 class="blog-post-title">{{ data_blog.title }}</h2>
<p class="blog-post-meta">{{ data_blog.date_published }} {{ data_blog.author }}</p>
<p>{{ data_blog.content }}</p>
{% endblock %}
how do i show foreignkey and manaytomany fieds after this?
TBH this is much easier if you use class based views.
The view would simply be:
class BlogContentDetail (DetailView):
model = BlogContent
The url call would be url(r'^blog-detail/(?P<pk>\d+)/$, BlogContentDetail.as_view(), name="blog_detail")
Your html file should be called blogcontent_detail.html and held within the app subfolder in the templates folder
The template would then be:
{% extends 'base.html' %}
{% block body_base %}
<img class="card-img-top img-responsive" src={{ object.image.url }} alt="Card image cap">
<h2 class="blog-post-title">{{ object.title }}</h2>
<p class="blog-post-meta">{{ object.date_published }} {{ object.author }}</p>
<p>{{ object.content }}</p>
{% for tag in object.tags_set.all %}{{ tag }}{% endfor %}
{% endblock %}
You can iterate the ManyToMany Field in this way
{% for tags in data_tag.tag.all %}
<p > {{tags}} </ p>
{% endfor %}
For foreign key
{{data_comment.comments}}

Display detail page for model using django-mptt-urls

Im trying to access the detailpage of a photo instance, but I can't seem to get it to work. (The category detail page works great!)
I would like to access http//domain.com/main-category/sub-cat/sub-sub-cat/photo-slug/
Models.py:
from mptt.models import MPTTModel, TreeForeignKey
class Category(MPTTModel):
name = models.CharField('category name', max_length=32)
parent = TreeForeignKey('self', null=True, blank=True, verbose_name='parent category', related_name='categories')
slug = models.SlugField(unique=True)
def get_absolute_url(self):
return reverse('gallery', kwargs={'path': self.get_path()})
class Photo(models.Model):
name = models.CharField('photo name', max_length=32)
parent = TreeForeignKey(Category, verbose_name='parent category', related_name='photos')
slug = models.SlugField()
class Meta:
unique_together = ('slug', 'parent')
urls.py:
url(r'^(?P<path>.*)', mptt_urls.view(model='gallery.models.Category', view='gallery.views.category', slug_field='slug'), name='gallery'),
views.py:
def category(request, path, instance):
return render(
request,
'gallery/category.html',
{
'instance': instance,
'children': instance.get_children() if instance else Category.objects.root_nodes(),
}
)
How is it possible to access the photo model using mtpp-urls ?
Edit 1:
Sorry, when I try a url like http//domain.com/main-category/sub-cat/sub-sub-cat/photo-slug The template display the Gallery main page because there is no instance when I try the url with the photo-slug (and yes, the photo has the category as a parent :)
Here is the category.html template:
<html>
<head>
<title>{% if instance %}{{ instance.name }}{% else %}Gallery main page{% endif %}</title>
</head>
<body>
<h3>{% if instance %}{{ instance.name }}{% else %}Gallery main page{% endif %}</h3>
Gallery main page
{% for ancestor in instance.get_ancestors %}
> {{ ancestor.name }}
{% endfor %}
> <strong>{{ instance.name }}</strong>
<h4>Subcategories:</h4>
<ul>
{% for child in children %}
<li>{{ child.name }}</li>
{% empty %}
<li>No items</li>
{% endfor %}
</ul>
<h4>Photos:</h4>
<ul>
{% for object in instance.photos.all %}
<li>{{ object.name }}</li>
{% empty %}
<li>No items</li>
{% endfor %}
</ul>
</body>
</html>
The reason why it doesn't work is that MPTT only works on one model at a time, in that case the gallery, not the photo.
So actually, in your models the Gallery is NOT the parent of the photo, but just a foreign key on the photo.
If you know that the last element of the slug is always a photo, you could probably create an intermediate view like this:
urls.py:
url(r'^(?P<path>.*)', views.photo, name='photo'),
views.py:
def photo(self, path=''):
path_parts = path.split('/')
gallery_path = '/'.join(path_parts[:-1])
photo_slug = path_parts[-1]
return mptt_urls.view(model='gallery.models.Category', view='gallery.views.photo_in_category', slug_field='slug')({'path': gallery_path, 'photo_slug': photo_slug})
def photo_in_category(request, path, gallery_instance, photo_slug=None):
photo_instance = Photo.objects.get(parent=gallery_instance, slug=photo_slug)
...
Otherwise, you may need to differentiate the URLS (which would also bring simpler code):
urls.py:
url(r'^photo/(?P<path>.*)/(?P<photo_slug>[-\w]+)/$', mptt_urls.view(model='gallery.models.Category', view='gallery.views.photo_in_category', slug_field='slug'), name='photo'),
url(r'^gallery/(?P<path>.*)/$', mptt_urls.view(model='gallery.models.Category', view='gallery.views.category', slug_field='slug'), name='gallery'),

how to filter story by it's belonging tag

I have two models news and category, and in news I have foreignkey of category. I know how to display news with same category in a single template. but furthermore, in my home page I'm trying to display featured news of each category. this is where I'm having problem.
this is my models.py
class News(models.Model):
title = models.CharField(max_length=120)
content = models.TextField()
category = models.ForeignKey("Tag")
active = models.BooleanField(default=True)
featured = models.BooleanField(default=False)
top = models.BooleanField(default=False)
slug = models.CharField(max_length=255, unique=True)
featuredInCat = models.BooleanField(default=False)
objects = StoryManager()
class NewsQueryset(models.query.QuerySet):
def active(self):
return self.filter(active=True)
def featuredInCat(self):
return self.filter(featuredInCat=True)
class NewsManager(models.Manager):
def get_queryset(self):
return NewsQueryset(self.model, using=self._db)
def get_featuredInCat(self):
return self.get_queryset().active().featuredInCat()
def all(self):
return self.get_queryset().active()
class Category(models.Model):
title = models.CharField(max_length=120)
description = models.TextField(max_length=5000, null=True, blank=True)
In views.py
def category_list(request):
categoryList = NewsCategory.objects.all()
featuredInCat = News.objects.get_featuredInCat()
context = {
"featuredInCat":featuredInCat
"categoryList":categoryList,
}
return render(request,"news/category_list.html", context)
In my template
{% for category in categoryList %}
<div class='col-sm-4'>
<div id="container">{{category.title}}</h1>
<ul>
{% for x in featuredInCat %}
{{x.title}}</li>
{% endfor %}
</ul>
</div>
<hr>
</div>
{% endfor %}
then this shows the featuredInCat in every category where featuredInCat should be shown only in its Category section.
how do I fix this?
Take a look at the built-in regroup template tag of django. You will need to change your template to something like this:
{% regroup featuredInCat by category as news_list %}
<ul>
{% for news in news_list %}
<li>{{ news.grouper.title }}
<ul>
{% for item in news.list %}
<li>{{ item.title }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
You can change your for loop to iterate over the correct objects
{% for x in category.news_set.get_featuredInCat %}
You won't need the context variable anymore

Categories

Resources