Home > database >  How to Call Two Fields From One Model in Django View
How to Call Two Fields From One Model in Django View

Time:01-28

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()
  • Related