I have an Image model and a Category model. I want to display only images of the corresponding category in my category_detail view.
models.py
class Category(models.Model):
category_title = models.CharField(max_length=200)
category_image = models.ImageField(upload_to="category")
category_description = models.TextField()
slug = models.SlugField(max_length=200, unique=True, default=1)
class Meta:
verbose_name_plural = "Categories"
def __str__(self):
return self.category_title
class Image(models.Model):
category = models.ForeignKey(Category, on_delete="CASCADE")
image = models.ImageField()
caption = models.CharField(max_length=250)
class Meta:
verbose_name_plural = "Images"
def __str__(self):
return str(self.image)
views.py
def category_detail_view(request, slug):
category = get_object_or_404(Category, slug=slug)
context = {
"gallery": Image.objects.filter(Category),
}
return render(request, 'main/category_detail.html', context)
category_detail.html
{% for image in gallery %}
<div class="col-md-4">
<a href="{{ image.url }}"> <img src="{{ image.url }}" class="img-responsive img-thumbnail" width="304" height="236"/>
</a>
</div>
{% endfor %}
You can filter these with:
def category_detail_view(request, slug):
category = get_object_or_404(Category, slug=slug)
context = {
'gallery': Image.objects.filter(category=category),
}
return render(request, 'main/category_detail.html', context)
or without fetching the category in a separate query:
You can filter these with:
def category_detail_view(request, slug):
context = {
'gallery': Image.objects.filter(category__slug=slug),
}
return render(request, 'main/category_detail.html', context)
Related
i am trying to show data from multiple models in one single view and one single template and i succeed with that but i have problem , the problem is posts from android model keep show at first because i have added android first in html page but what i want to do is show posts by date published what should i do
models.py :
class android(models.Model):
name = models.CharField(max_length=50,default="")
slug = models.SlugField(max_length=250,default="")
post_date = models.DateTimeField(auto_now_add=True, null=True, blank=True)
def get_image(self):
if self.app_image and hasattr(self.app_image, 'url'):
return self.app_image.url
else:
return '/path/to/default/image'
def __str__(self):
return self.name
class Meta:
ordering = ('-post_date',)
class PCgames(models.Model):
name = models.CharField(max_length=50,default="")
slug = models.SlugField(max_length=250,default="")
post_date = models.DateTimeField(auto_now_add=True, null=True, blank=True)
def get_image(self):
if self.app_image and hasattr(self.app_image, 'url'):
return self.app_image.url
else:
return '/path/to/default/image'
def __str__(self):
return self.name
class Meta:
ordering = ('-post_date',)
views.py :
def home_page(request):
pcgamesforhome = PCgames.objects.all()
androidforhome = Android.objects.all()
context = {'pcgamesforhome' : pcgamesforhome,'androidforhome' : androidforhome}
return render(request,'html_file/home.html',context=context)
home.html :
<div class="container">
<div class='row'>
{% for android in androidforhome %}
<div class='col-xs-12 col-sm-6 col-md-4 website-thumb'>
<a href="{{ android.slug }}">
<img src="{{ android.get_image }}" class='image_control_for_home_page_pc_games' alt=''> </a>
<h3>{{ android.name }}</h3> </div>
{% endfor %}
</div>
<div class="container">
<div class='row'>
{% for home_page in pcgamesforhome %}
<div class='col-xs-12 col-sm-6 col-md-4 website-thumb'>
<a href="{{ home_page.slug }}">
<img src="{{ home_page.get_image }}" class='image_control_for_home_page_pc_games' alt=''> </a>
<h3>{{ home_page.name }}</h3> </div>
{% endfor %}
</div>
so now what should i do to show posts from all models order by date ?
your database structure is wrong. instead of having two model for android and PC, you can have one model and a field specifying object type with choices
class Foo(models.Model):
Type = (
('android', 'android'),
('pc', 'pc'),
)
name = models.CharField(max_length=50,default="")
slug = models.SlugField(max_length=250,default="")
post_date = models.DateTimeField(auto_now_add=True, null=True, blank=True)
type = models.CharField(max_length=10, choices=Type)
if you like to have a special field for each android or pc, you can create fields with blank and null true attr.
views.py:
# get all of them and order them by creation date
Foo.obejcts.all().order_by('-post_date')
# get android type objects
Foo.objects.filter(type='android')
# get pc type objects
Foo.objects.filter(type='pc')
a basic example would be
class Category(models.Model):
name = models.CharField(max_length=30)
slug = models.SlugField(max_length=50)
def __str__(self):
return self.name
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField(blank=True)
post_date = models.DateTimeField(auto_now_add=True, null=True, blank=True)
slug = models.SlugField(max_length=50)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
def __str__(self):
return self.title
class Meta:
#recent post in top
ordering = ['-post_date']
in views to filter based on category:
pc_games = Post.objects.select_related("category_set").filter(category__name='pc_games')
android = Post.objects.select_related("category_set").filter(category__name='android')
In my model I have a ManyToManyField to select related products. I'm wondering what would be the best way to bring these into my view and render them in my template.
models.py
class Product(models.Model):
title = models.CharField(max_length=80)
category = models.ManyToManyField(ProductCategory)
featured_image = models.ImageField(upload_to=image_dir)
about_this_product = models.TextField()
standard_features = models.TextField(null=True)
featured = models.BooleanField(default=False)
related_models = models.ManyToManyField("self", blank=True, null=True)
model_slug = AutoSlugField(null=True, default=None,
unique=True, populate_from='title')
class Meta:
verbose_name_plural = "Products"
def __str__(self):
return self.title
views.py
def model_detail_view(request, category_slug, model_slug):
product_model = get_object_or_404(Product, model_slug=model_slug)
context = {
"title": "Products | %s" % product_model.title,
"product": product_model,
}
return render(request=request, template_name='main/product_model_detail.html', context=context)
You can use .prefetch_related(..) just like you do on any one-to-many relation in the view:
def my_view(request):
products = Product.objects.prefetch_related('related_models')
return render(request, 'some_template.html', {'products': products})
Then in the template, you can iterate over the .related_models collection:
{% for product in products %}
{{ product.title }}
related:
{% for rel in product.related_models.all %}
{{ rel.title }}
{% endfor %}
{% endfor %}
I'm trying to use django formset for the first time in order to combine both forms on the same page.
My form is well displayed but I don't overvome to save data in my database. When I click on submit button, nothing happens.
This is my model.py file :
class Publication(models.Model):
title = models.CharField(max_length=512, verbose_name=_('title'), null=False)
category = models.ForeignKey(Category, verbose_name=_('category'), null=False)
creation_date = models.DateTimeField(auto_now_add=True, verbose_name=_('creation date'), null=False)
modification_date = models.DateTimeField(auto_now=True, verbose_name=_('modification date'), null=False)
class Meta:
verbose_name = _('publication')
verbose_name_plural = _('publication')
def __str__(self):
return f"{self.title}"
class Document(models.Model):
FORMAT_CHOICES = (
('pdf', 'pdf'),
('epub', 'epub'),
)
format = models.CharField(max_length=10, verbose_name=_('format'), choices=FORMAT_CHOICES, null=False)
title = models.CharField(max_length=512, verbose_name=_('title'), null=False)
publication = models.ForeignKey(Publication, verbose_name=_('publication'), null=False)
upload = models.FileField(upload_to='media/', default="")
creation_date = models.DateTimeField(auto_now_add=True, verbose_name=_('creation date'), null=False)
modification_date = models.DateTimeField(auto_now=True, verbose_name=_('modification date'), null=False)
class Meta:
verbose_name = _('document')
verbose_name_plural = _('document')
def __str__(self):
return f"{self.age_id} : {self.title}"
My form file is very simple too with defined Formset :
class PublicationForm(forms.ModelForm):
class Meta:
model = Publication
fields = ('title', 'category')
class DocumentForm(forms.ModelForm):
class Meta:
model = Document
fields = ['publication', 'format', 'title', 'upload']
DocumentFormSet = inlineformset_factory(Publication, Document, form=DocumentForm, extra=1)
My view is a bit more complicated :
class PublicationCreateUpdateView(AgePermissionRequiredMixin, UpdateView):
""" Display a form to create or update a publication
Only for age admin.
**Context**
``subtitle``
Title of the page
**Template:**
:template:`app/category_form.html`
"""
model = Publication
form_class = PublicationForm
success_url = reverse_lazy('app:app-publication-list')
template_name = 'app/publication_form.html'
permission_required = 'publication.change_webapplication'
def get_object(self, queryset=None):
try:
return super(PublicationCreateUpdateView, self).get_object(queryset)
except AttributeError:
return None
def get_title(self):
if self.object:
return _('Edit publication: ') + str(self.object)
return _('Add new publication')
def get_context_data(self, **kwargs):
context = super(PublicationCreateUpdateView, self).get_context_data(**kwargs)
if self.request.POST :
context['documents'] = DocumentFormSet(self.request.POST)
else :
context['documents'] = DocumentFormSet()
context.update({
'subtitle': self.get_title(),
})
return context
def form_valid(self, form):
context=self.get_context_data()
documents = context['documents']
with transaction.atomic():
self.object = form.save()
if documents.is_valid():
documents.instance = self.object
documents.save()
return super(DocumentCreateUpdateView, self).form_valid(form)
And finally my template looks like this :
{% extends "publication/base_backend.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block main %}
<form method="post" novalidate>
{% csrf_token %}
{% crispy form %}
{{ documents.management_form }}
{{ documents.non_form_errors }}
{% crispy documents %}
<br>
<input type="submit" class="btn btn-default" value="{% trans 'Save' %}" />
{% trans 'Cancel' %}
</form>
{% endblock main %}
I don't understand where I could make a mistake, furthermore I'm pretty new with Django Class Based View.
i want to get the images form the image model in the template.
class Products(models.Model):
category = models.ForeignKey(Category)
name= models.CharField(max_length=120, unique=True)
slug = models.SlugField(unique = True)
price = models.IntegerField(default=100)
class Image(models.Model):
property = models.ForeignKey(Products, related_name='images')
image = models.ImageField(upload_to='static/images/home',blank=True,null=True)
views.py
def index(request):
queryset = Products.objects.all()
return render_to_response('site/index.html',
locals(),
context_instance=RequestContext(request))
{% for query in queryset %}
<img src='/ {{ query.????? }} ' alt="" width = 'auto' height='340'/>
{% endfor %}
i want to get the images which is connected to that product
i have readed that link
i have tried:
{% for query in queryset %}
<img src='/ {{ query.images_all.0.image }} ' alt="" width = 'auto' height='340'/>
{% endfor %}
but no success ..
just try to understand the model that how i get the image url from models which related with foreignkey relationship.
my models:
class Product(models.Model):
title = models.CharField(max_length = 400)
slug = models.SlugField(max_length = 400,unique=True,null=True,blank=True)
is_popular = models.BooleanField(default=True)
category = models.ForeignKey(Category,on_delete=models.CASCADE)
subcategory = models.ForeignKey(Subcategory,on_delete=models.CASCADE,null=True,blank=True)
childcategory = models.ForeignKey(Childcategory,on_delete=models.CASCADE,null=True,blank=True)
brand = models.ForeignKey(Brand,on_delete=models.CASCADE,null=True,blank=True)
description = models.TextField()
is_active = models.IntegerField(choices=STATUS_CHOICES)
created_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
def save(self, *args, **kwargs):
self.slug = unique_slug_generator(self)
super(Product, self).save(*args, **kwargs)
def show_image(self):
return self.productmeaserment_set.first().first_image()
class ProductMeaserment(models.Model):
product = models.ForeignKey(Product,on_delete=models.CASCADE)
measerment = models.ForeignKey(Measerment,on_delete=models.CASCADE,null=True,blank=True)
selling_price = models.DecimalField(max_digits=20,decimal_places=2)
offer_price = models.DecimalField(max_digits=20,decimal_places=2)
available_quantity = models.IntegerField();
is_active = models.IntegerField(choices=STATUS_CHOICES)
created_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.measerment.name
def first_image(self):
return self.productmeasermentimage_set.first()
class ProductMeasermentImage(models.Model):
productmeaserment = models.ForeignKey(ProductMeaserment,on_delete=models.CASCADE)
image = models.FileField(upload_to='uploads/products')
is_active = models.IntegerField(choices=STATUS_CHOICES)
created_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.productmeaserment.product.title
views.py
from products.models import Product
def adminpanel(request):
products=Product.objects.all()
return render(request,'adminpanel/index.html',{'productsall':products})
templates/adminpanel/index.html
{% for item in productsall %}
<tr>
<div class="border1">
<td class="image-cell">
<img src="{{item.show_image.image.url}}"> #this is how i got image url.
</td>
</div>
<td data-label="title">{{item.title}}</td>
<td data-label="category">{{item.category}}</td>
<td data-label="subcategory">{{item.subcategory}}</td>
<td data-label="brand">
{{item.brand}}
</td>
<td data-label="description">
{{item.description}}
</td>
<td class="created">
{{item.created_date}}
</td>
</tr>
<tr>
{% endfor %}
There is so much wrong with your code, I suggest that you do the Django Tutorial first.
https://docs.djangoproject.com/en/1.8/intro/tutorial01/
But if you wan't it working, here is how:
models.py
class Product(models.Model):
category = models.ForeignKey(Category)
name= models.CharField(max_length=120, unique=True)
slug = models.SlugField(unique = True)
price = models.IntegerField(default=100)
def first_image(self):
# code to determine which image to show. The First in this case.
return self.images[0]
class ProductImage(models.Model):
image = models.ImageField(upload_to='static/images/home',blank=True,null=True)
product = models.ForeignKey(Product, related_name='images')
views.py
def index(request):
queryset = Products.objects.all()
return render_to_response('site/index.html', {'products': queryset})
index.html
{% for product in products %}
<img src="{{ product.first_image.src }}" alt="" width="auto" height="340"/>
{% endfor %}
I m beginner.
I'm trying to access a related item of the model Product in the template layer of a ProductDetailView. How can I retrieve the ImageFields of the Products' Brand's BrandImages? I have to traverse one forward and one reverse ForeignKey.
Edited to include get_logo_url
What is wrong with the get_logo_url function?
products/models.py
class Product(models.Model):
brand = TreeForeignKey('Brand', verbose_name='parent category', related_name='products', default='')
title = models.CharField(max_length=120)
description = models.TextField(max_length=500, blank=True, null=True)
price = models.DecimalField(decimal_places=2, max_digits=20)
active = models.BooleanField(default=True)
category = TreeForeignKey('Category', verbose_name='parent category', related_name='products', default='')
slug = models.SlugField(default='')
objects = ProductManager()
class Meta:
unique_together = ('slug', 'category')
def get_absolute_url(self):
return reverse("product_detail", kwargs={"pk":self.pk})
def __unicode__(self):
return self.title
def get_image_url(self):
img = self.productimage_set.first()
if img:
return img.image.url
return img
brands/models.py
def image_upload_to(instance, filename):
title = instance.brand.title
slug = slugify(title)
file_extension = filename.split(".")[1]
new_filename = "%s.%s" % (instance.id, file_extension)
return "products/%s/%s" % (slug, new_filename)
class BrandImage(models.Model):
brand = models.ForeignKey('Brand', related_name='brandimages')
is_slider = models.BooleanField(default=False)
is_featured = models.BooleanField(default=False)
is_logo = models.BooleanField(default=False)
image = models.ImageField(upload_to=image_upload_to)
def __unicode__(self):
return self.brand.title
def get_logo_url(self):
if is_logo:
img = self.brandimage_set.first()
if img:
return img.image.url
return img
def thumb(self):
if self.image:
return u'<img src="%s" width=120 height=120 />' % (self.image.url)
else:
return u'No image file found'
thumb.allow_tags = True
class Brand(MPTTModel):
title = models.CharField(max_length=50, default='')
parent = TreeForeignKey('self', null=True, blank=True, verbose_name='parent brand', related_name='brands')
slug = models.SlugField(unique=True)
def get_absolute_url(self):
return reverse('brands', kwargs={'path': self.get_path()})
def __unicode__(self):
return self.title
template
<div class="rightpart">
<div class="prodbrand h2">
<h1>{{ product.brand }}</h1>
<div class="brandlogo">
{% for image in product.brand.brandimages.all %}
<img src="{{image.get_logo_url }}"/>
{% endfor %}
</div>
</div>
<div class="prodtitle"><h2>{{ product.title }}</h2>
</div>
views.py
class ProductDetailView(DetailView):
model = Product
template_name = 'products/product.html'
def get_context_data(self , *args , **kwargs):
context = super(ProductDetailView , self).get_context_data(*args,**kwargs)
instance = self.get_object()
context["related"] = Product.objects.get_related(instance)
return context
urls.py
url(r'^$', ProductDetailView.as_view(), name='products'),
is there a way to access foreign fields in django templates like this?
As you are using a ListView to display your products there's several things to notice:
get_context_data() must return a dictionary: return context is missing
super().get_context_data should be called with *args,**kwargs incase you decide to subclass the ProductListView at a later point in time.
super().get_context_data will contain a object_list key which contains the list of objects returned by get_queryset(), in your case objects of class Product.
When accessing a property from a template, django will attempt to call it without parameters if it is callable. This is often useful e.g.: for {{ request.user.is_authenticated }} or product.brand.brandimages.all
Your template should look like this:
product_list.html
{% for product in object_list %}
<div class="rightpart">
<div class="prodbrand h2">
<h1>{{ product.brand }}</h1>
<div class="brandlogo">
{% for image in product.brand.brandimages.all %}
<img src="{{image.image.url}}"/>
{% endfor %}
</div><!-- End brandlogos -->
</div><!-- End prodbrand -->
<div class="prodtitle">
<h2>{{ product.title }}</h2>
</div>
</div><!-- End rightpart -->
{% endfor %}
Take into account that this will incur several database lookups from the template. You generally want to avoid the case that your presentation layer reaches into the database, which is why you should prefer to do the database lookup in the corresponding View. Also for property access consider using select_related and prefetch_related as appropriate to avoid unneeded database queries.
views.py
class ProductListView(ListView):
model = Product
queryset = Product.objects.all().active()
def get_context_data(self, *args, **kwargs):
context = super(ProductListView, self).get_context_data(*args, **kwargs)
context["now"] = timezone.now()
return context
def get_queryset(self, *args, **kwargs):
# We call super() for potential subclasses
queryset = super(ProductListView, self).get_context_data(*args, **kwargs)
queryset.prefetch_related('brand__brandimages')
return queryset