Display detail page for model using django-mptt-urls - python

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'),

Related

How to display a gallery of images of a product after clicking on the first image?

So in short, I have a ListView in Django which displays pictures with tables on the website. Then I have a DetailView where I am placing a second webpage to use with slugs but I guess my logic is wrong.
I want to be able to click on a particular picture/ table and this would redirect me to another page( possible created with slug) where I can display more pictures of the same table. I have created everything so far but I am thinking my logic is wrong. You don't have to write code, just please explain what is the correct way of doing it since I am doing it for the first time.
First I created a Categories model which lists categories such as: tables, kitchens, wardrobes, bedrooms. I then created Image category where I would have title and image and so on but this was okay for one of the views but for this one I want to display multiple pictures as I mentioned and I saw some code which enabled me to have multiple images.
views.py
class TableCategoryListView(ListView):
model = Images
template_name = 'main/projects/tables.html'
context_object_name = 'category_images'
queryset = Images.objects.filter(category__category_title="tables")
class TablesDetailView(DetailView):
model = Images
template_name = "main/projects/tables_slug.html"
url.py
path('proekti/masi/', TableCategoryListView.as_view(), name='tables'),
path('proekti/masi/<slug:slug>', TablesDetailView.as_view(), name='table'),
models.py
class Category(models.Model):
category_title = models.CharField(
max_length=50
)
def __str__(self):
return self.category_title
class Images(models.Model):
title = models.CharField(
blank=True,
null=True,
max_length=50,
)
category_image = models.ImageField(
blank=True,
null=True,
)
category = models.ForeignKey(
Category,
on_delete=models.CASCADE)
def __str__(self):
return self.title
def __unicode__(self):
return self.title
slug = models.SlugField(
null=True,
)
def get_absolute_url(self):
return reverse("article-detail", kwargs={"slug": self.slug})
class PhotoAlbum(models.Model):
menu = models.ForeignKey(Images, on_delete=models.CASCADE)
image = models.ImageField()
order = models.IntegerField(
blank=True,
null=True,
)
def __unicode__(self):
return self.menu
class Meta:
ordering = ('order',)
I read this would help me to easily add multiple pictures.
admin.py
#admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
pass
class ImagesForm(forms.ModelForm):
model = Images
class Media:
js = (
'/static/js/jquery-latest.js',
'/static/js/ui.base.js',
'/static/js/ui.sortable.js',
'/static/js/menu-sort.js',
)
class PhotoAlbumInline(admin.StackedInline):
model = PhotoAlbum
admin.site.register(
Images,
inlines=[PhotoAlbumInline],
form=ImagesForm,
list_filter=('category',),
search_fields=('title',)
)
"""
/* menu-sort.js */
jQuery(function($) {
$('div.inline-group').sortable({
/*containment: 'parent',
zindex: 10, */
items: 'div.inline-related',
handle: 'h3:first',
update: function() {
$(this).find('div.inline-related').each(function(i) {
if ($(this).find('input[id$=name]').val()) {
$(this).find('input[id$=order]').val(i+1);
}
});
}
});
$('div.inline-related h3').css('cursor', 'move');
$('div.inline-related').find('input[id$=order]').parent('div').hide();
});
"""
template tables.html
{% extends 'base.html' %}
{% block page_content %}
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'css/masi.css' %}">
<div class="row">
{% for image in object_list %}
{% if forloop.counter0|divisibleby:1 %}
<div class="column" style="background-color: whitesmoke">
<img src="{{ image.category_image.url }}" alt="pic">
<p>
</div>
{% endif %}
{% endfor %}
</div>
{% endblock %}
template tables_slug.html --> where I would want to display all the images of a particular table with it doesn't show me one of the tables and doesn't show all the images I have uploaded in the admin page.
{% extends 'base.html' %}
{% block page_content %}
{% for image in category_images %}
<div>
<h2>{{ object.title }} </h2>
<img src="{{ object.category_image.url }}" alt="pic">
</div>
{% endfor %}
{% endblock %}
Updated
You can do this:
In your TableCategoryListView, override the get_context_data like so:
class TableCategoryListView(ListView):
model = Images
template_name = 'main/projects/tables.html'
context_object_name = 'category_images'
class TableCategoryListView(ListView):
model = Images
template_name = 'main/projects/tablesdetail.html'
context_object_name = 'detail_cat_img'
def get_context_data(self, **kwargs):
context = super(TableCategoryListView, self).get_context_data(**kwargs)
context['detail_category'] = Images.objects.all() # this gives you all the items from the Images model
context['xtr_images'] = PhotoAlbum.objects.all() # the logic to render only those photos related to the current view goes here. You have to figure this out yourself
return context # this returns the two objects above xtr_images and detailcategory
You can use the slice operator to determine number of images to show per page either in your views or on the template itself like so:
Entry.objects.all()[:5] # prints four images
This should do the trick.
Thanks for your answer.I just solved the problem I believe with simpler code.
I was missing "related_names" in the model for the relation.
models.py
class PhotoAlbum(models.Model):
menu = models.ForeignKey(
Images,
on_delete=models.CASCADE,
related_name="child_images",
)
image = models.ImageField()
order = models.IntegerField(
blank=True,
null=True,
)
def __unicode__(self):
return self.menu
class Meta:
ordering = ('order',)
and for the template then: tables_slug.html
{% extends 'base.html' %}
{% block page_content %}
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'css/masi.css' %}">
{% for image in image.child_images.all %}
<div class="column">
<p>
<img src="{{ image.image.url }}" alt="pic">
</p>
</div>
{% endfor %}
{% endblock %}

How to access child class object that inherits parent class?

I have parent class and child class, that inherits parent class. And that is okay, I can iterate with for loop. Now I want to access child class (example: 'product_type' So basically, I'm confused how we inherits stuff from child class inside the same loop...
views.py
from django.views import generic
from . models import Category
from django.shortcuts import render
class CategoryListView(generic.ListView):
model = Category
template_name = 'category_list.html'
models.py
from django.db import models
import uuid
class Category(models.Model):
name = models.CharField(max_length=100, help_text='Category name')
def __str__(self):
return self.name
class Meta:
verbose_name_plural = 'Categories'
class Product(models.Model):
product_name = models.CharField(max_length=255, help_text='Product name')
# product_spec = models.TextField(max_length=5000, help_text='Product specs')
product_type = models.ForeignKey('Category', on_delete=models.SET_NULL, null=True)
def __str__(self):
return self.product_name
category_list.html
{% extends 'base.html' %}
{% block body %}
{% for page in category_list %}
<li>{{ page.name }}</li>
<li>{{ page.product_name }} # <--------------- Now this is the point of
#my problem, I want to get
#product name from child
#class
#this returns empty <li>
{% endfor %}
{% endblock %}
you can to this
{% extends 'base.html' %}
{% block body %}
{% for page in category_list %}
<li>{{ page.name }}</li>
<li>{{ page.product_set.first.product_name }}
product name from child class, this returns empty <li>
{% endfor %}
{% endblock %}
First off change your product_type name to just category its way easier to understand and add an attribute related_name to it like this:
class Product(models.Model):
name = models.CharField(max_length=255, help_text='Product name')
category = models.ForeignKey('Category', on_delete=models.SET_NULL, null=True, related_name='products')
then in your template
{% for category in category_list %}
{{ category.name }}
{% for product in category.products.all %}
{{ product.name}}
... other product data
{% endfor %}
{% endfior %}
product_typein Product is a ForaignKey which means their will be multiple products having same Category so their exist two solutions
make product_type in Product one to one key, with this you shuld get single name by {{ page.product.product_name }}
print list of all products of the category, you can do this by iterating page.product_set as it is a list (iterable) with for loop.

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}}

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

Django foreign key object image in template

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 %}

Categories

Resources