开发者

Trying to filter image by category in Django

I am trying to filter an image through a category. It works but not the way I want it to. Here are how my models are setup:

class Image(models.Model):
    CATEGORY_CHOICES = (
    ('Cover', 'Cover'),    
    ('Scan', 'Scan'),
    ('Other', 'Other'),
    )
    title = models.CharField(max_length=256)
    image = models.ImageField(upload_to="images/")
    category = models.CharField(max_length=10, choices=CATEGORY_CHOICES)
    contributor = models.ManyToManyField(Contributor, blank=True, null=True)
    date_added = models.DateField(auto_now_add=True)    
    def __unicode__(self):
        return self.title
    class Meta:
        ordering = ['title']


class Issue(models.Model):

    ...

    images = models.ManyToManyField(Image, related_name="images_inc", blank=True, null=True)

    ....

    def __unicode__(self):
        return u'%s #%s' % (self.title, self.number)
    def get_absolute_url(self):
        return "/issues/%s" % self.slug     
    class Meta:
        ordering = ['-date_added']

Views.py:

def issue(request, issue_slug):
    issue = get_object_or_404(Issue, slug=issue_slug)
    cover = Image.objects.filter(category='Cover')
    scan = Image.objects.filter(category='Scan')
    return render_to_response('comics/issue_detail.html', {'issue': issue, 'cover': cover, 'scan': scan}, context_instance=RequestContext(request))

I am trying to filter it by Cover or Scan, as you can see, but when I put this into my template:

{{ cover }} or {{ scan }}

It returns:

<Image: Astonishing X-Men 1 Cover A>] [<Image: Astonishing X-Men 1, teamshot>]

I need it to return the image URL, obviously. Adding {{ cover.url }} doesn't work.

Oh, and I just realized it does not display the specific image that is in the issue. It displays ALL images that categorized as either Scan 开发者_运维百科or Cover.


In your current code, you're returning all the images, even the ones that aren't associated with your chosen comic issue. I'm assuming you want the ones for the selected issue. You probably want to do this instead:

def issue(request, issue_slug):
    issue = get_object_or_404(Issue, slug=issue_slug)
    try:
        cover = issue.images_inc.filter(category='Cover')[0]
    except IndexError:
        cover = None
    try:
        scan = issue.images_inc.filter(category='Scan')[0]
    except IndexError:
        scan = None
    return render_to_response('comics/issue_detail.html', {'issue': issue, 'cover': cover, 'scan': scan}, context_instance=RequestContext(request))

Then, in the template:

{% if cover.image %}
    <img src="{{ cover.image.url }}" alt="{{ cover.image.title }}" />
{% endif %}

{% if scan.image %}
    <img src="{{ scan.image.url }}" alt="{{ scan.image.title }}" />
{% endif %}

Update

If you do want more than one cover or scan, then you don't want to get only the first item. And really, you should probably just move this logic to models.py to avoid possible code duplication.

Something like this would be better:

# models.py


class Issue(models.Model):
    ...
    def scans(self):
        return self.images.filter(category='Scan')

    def covers(self):
        return self.images.filter(category='Cover')

# views.py

def issue(request, issue_slug):
    issue = get_object_or_404(Issue, slug=issue_slug)
    return render_to_response('comics/issue_detail.html', {'issue': issue }, context_instance=RequestContext(request))

Then, in the template:

<ul>
{% for cover in issue.covers %}
    <li><img src="{{ cover.image.url }}" alt="{{ cover.image.title }}" /></li>
{% empty %}
    <li>No cover</li>
{% endfor %}
</ul>

<ul>
{% for scan in issue.scans %}
    <li><img src="{{ scan.image.url }}" alt="{{ scan.image.title }}" /></li>
{% empty %}
    <li>No scans</li>
{% endfor %}
</ul>


filter always returns the list of matches in an array.

If you just want the first match, you could do something like this

 cover = issue.images.filter(category='Cover')[:1][0]
 scan = issue.images.filter(category='Scan')[:1][0]

But that will throw an exception if there is no match, so maybe better to wrap in in a try except such as

try:
     cover = issue.images.filter(category='Cover')[:1][0]
except:
     cover = None 

In the template, since cover and scan represent image objects, you can get the url with this syntax:

{{ cover.image.url }} or {{ scan.image.url }}

The alternative if you want to see all of the images is to load covers and scans (plural) and check to see if they are non empty in your template. There is no need to except for the index error here, and it is much simpler.

In this case you would do:

 covers = issue.images.filter((category='Cover'))

And then in the template:

{% if covers %}
    {% for cover in covers %}
          {{cover.image.url}} - {{cover.title}}
    {% endfor %}
{% endif %}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜