I now have a model and I want to display two fields of it in the same view.Then display them in the details template.But the result returns an empty in template.What is the best way to do that?
my model:
class Book(models.Model):
class Meta :
verbose_name_plural = 'Books'
category = models.ForeignKey(Categorie,on_delete=models.CASCADE,null=True,
related_name="apps")
book_slug = models.SlugField(blank=True,allow_unicode=True,editable=True)
book_title = models.CharField(max_length=50 , null=True)
book_picture = models.ImageField(upload_to='imgs' , null=True)
book_description = RichTextUploadingField(null=True,blank=True)
book_size = models.CharField(max_length=20 , null=True)
book_created_at = models.DateField(auto_now_add=True)
book_updated_at = models.DateField(auto_now=True)
book_auther = models.CharField(max_length=100 , null=True)
my views:
def book_details(requset ,book_slug):
book = get_object_or_404 (Book, book_slug = book_slug)
try :
book = Book.objects.filter(book_slug = book_slug)
except :
raise Http404
similar_books = Book.objects.filter(book_auther = book_slug) ------ >>> Here is my query
context ={
'book' :book,
'similar_books':similar_books,
}
return render( requset,'book.html',context)
my template:
<div >
{% for b in book %}
<div>
<img src="{{ b.book_picture.url }}" height="150"
width="150" alt="">
<a href="{{b.get_absolute_url}}">{{b.book_title}}</a>
</div>
{% endfor %}
</div>
<div >
{% for sb in similar_books%}
<div>
<img src="{{ sb.book_picture.url }}" height="150"
width="150" alt="">
<a href="{{sb.get_absolute_url}}">{{sb.book_title}}</a>
</div>
{% endfor %}
</div>
CodePudding user response:
First of all
book = get_object_or_404 (Book, book_slug = book_slug)
this is a get method, which returns a single instance of book if found (not a Queryset)
Then you are repeating the same thing, and in my opinion this piece of code can be discarded since it's a duplicate of the row above
try :
book = Book.objects.filter(book_slug = book_slug)
except :
raise Http404
Then in the template you don't have to cicle on book: that's a single object not an enumerable - queryset, so you should write
<div >
<div>
<img src="{{ book.book_picture.url }}" height="150"
width="150" alt="">
<a href="{{book.get_absolute_url}}">{{book.book_title}}</a>
</div>
</div>
About your second query, based on your example data you cannot extract data with a filter, but have to process in this way:
similar_books = []
for sb in Book.objects.all():
if sb.book_author in book_slug:
similar_books.append(sb)
CodePudding user response:
Insisted of using filter(book_slug = book_slug) use __icontains with Q object (use the each word in book_slug inorder to get maximum similar entries). for example : -
slugs = book_slug.split() # which will give list of slugs
condition = Q(book_slug__icontains=slugs[0])
for slug in slugs[1:]:
condition &= Q(book_slug__icontains=slug)
Book.objects.filter(condition).all()
if you wish to eliminate explicit loop like above you can use operator to do that.
import operator
slug_conditions = reduce(operator.and_, [Q(book_slug__icontains=slug) for slug in book_slug])
queryset = Profile.objects.filter(slug_conditions).all()