Search code examples
djangodjango-templatesdjango-media

Image does not get rendered in Django


I fiddled around with the django ImageField,
and I got following models for example

class Card(models.Model):
    name        =   models.TextField()
    mana        =   models.IntegerField()
    rarity      =   models.IntegerField(choices=RARITY_CHOICES)
    card_class  =   models.IntegerField(choices=CLASS_CHOICES)
    card_set    =   models.IntegerField(choices=SET_CHOICES)
    card_type   =   models.IntegerField(choices=TYPE_CHOICES)

    def __unicode__(self):
        return self.name

class Weapon(Card):
    damage      =   models.already created a deck with some cards in the django admin interface. Now finally I wanted to render it with a custom view in my template with this viewIntegerField()
    durability  =   models.IntegerField()
    image       =   models.ImageField(upload_to='/home/ubuntu/illuminated/media/images/weapons/')

class Deck(models.Model):
    name            =   models.CharField(max_length=20)
    spell_cards     =   models.ManyToManyField(Spell, blank=True)
    weapon_cards    =   models.ManyToManyField(Weapon, blank=True)
    minion_cards    =   models.ManyToManyField(Minion, blank=True)

I already created a deck with some cards in the django admin interface. Now finally I wanted to render it with a custom view in my template with this view

class ShowDeck(TemplateView):
    template_name = 'hsguides/deck.html'

    def get_context_data(self, **kwargs):
        context = super(ShowDeck, self).get_context_data(**kwargs)
        context['deck'] = Deck.objects.all()
        return context

And this simple template already created a deck with some cards in the django admin interface. Now finally I wanted to render it with a custom view in my template with this view

{% for foo in deck.all %}
  {{ foo.name }}
  <br>
  {% for weapon in foo.weapon_cards.all %}
    {{ weapon.name }}
    <img src="{{ weapon.image }}" height="{{ weapon.image.height }}" width="{{ weapon.image.width }}">
  {% endfor %}
{% endfor %}

The names are getting rendered, and when I have a look at the page source the image url, width and height as well but the image simply does not show up.
When I click on View Image in my browser I see the following error

Using the URLconf defined in illuminated.urls, Django tried these URL patterns, in this order:

^admin/
^account/
^guides/

The current URL, home/ubuntu/illuminated/media/images/weapons/Truesilver_Champion_Gold_ktmWGK8.png, didn't match any of these

It currently looks like this

enter image description here

The page source looks like this

  Basic Paladin
  <br>

    Truesilver Champion
    <img src="/home/ubuntu/illuminated/media/images/weapons/Truesilver_Champion_Gold_ktmWGK8.png" height="396" width="289">

Any kind of help is highly appreciated!


Solution

  • In short:


    Set the upload_to attribute to images/weapons/ and add

        url(r'^media/(?P<path>.*)$', 'django.views.static.serve',
            {'document_root': MEDIA_ROOT}),
    

    to your root urls.py.

    Also make sure in your settings you define MEDIA_ROOT and MEDIA_URL:

    BASE_DIR = os.path.dirname(os.path.dirname(__file__))
    MEDIA_URL = '/media/'
    MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
    

    Explanation:


    In your models.py you are setting the upload_to attribute of the ImageField in class Weapon to an absolute path on your local filesystem : /home/ubuntu/illuminated/media/images/weapons.

    In the context of your browser however any path starting with / is interpreted as absolute with regards to the host. In case your hostname is localhost and your server is running on port 8000 it will look for the file http://localhost:8000/home/ubuntu/......./weapons/file.jpg.

    When django processes the request it tries to match the requested path which starts with home, but as you have no route configured to resolve home you get this error.