R
R
Ruslan Ezhgurov2015-11-19 17:41:14
Django
Ruslan Ezhgurov, 2015-11-19 17:41:14

How to make django download and upload an image?

Good day, you need to save the image using the link in the ImageField field. I can't think of a way to do this at all. Tell me please!
Here is the function that I threw ( did according to the example ):

def baza(request):
  baza = urllib.request.urlopen("BAZA_URL").read().decode('utf-8-sig').replace(u'\xa0', ' ').replace(u'\r', ' ').replace(u'\n', ' ')
  baza = baza.split('<br>')
  for line in baza:
    line = line.split('--')
    try:
      categories = Categories.objects.get(name=line[0])
      img_url = line[1]
      content = urllib.request.urlopen(img_url).read()
      Item(categories=categories, img=content, name=line[2], text=line[3], options=line[4]).save()
    except:
      categories = Categories(name=line[0])
      img_url = line[1]
      content = urllib.request.urlopen(img_url).read()
      Item(categories=categories, img=content, name=line[2], text=line[3], options=line[4]).save()
  return HttpResponse(render_to_string('baza.html', locals()))

Answer the question

In order to leave comments, you need to log in

2 answer(s)
M
marazmiki, 2015-11-20
@Oyaseo

Even if you close your eyes to the design of the code, constant duplication, it is still very strange code with undefined behavior. And that's why:

try:
    categories = Categories.objects.get(name=line[0])    # Метка 1
      img_url = line[1]   # Метка 2
      content = urllib.request.urlopen(img_url).read()        # Метка 3
      Item(categories=categories, img=content, name=line[2], text=line[3], options=line[4]).save()
    except:
      categories = Categories(name=line[0])    # Метка 4
      img_url = line[1]
      content = urllib.request.urlopen(img_url).read()
      Item(categories=categories, img=content, name=line[2], text=line[3], options=line[4]).save()    # Метка 5
First of all, I want to pay attention to the line with the comment "Label 4". You, as I understand it, want to create a Categories model if it was not found in the "Label 1" line. Create something You created it, but did not save it! There is no such object in the database. So when you call save Item (see "Label 5") you can catch the error.
Or you may not catch it, because another situation is possible when the category (see "Label 1") was found, but the download image was determined incorrectly, and the download broke. Or the network is simply unavailable. In this case, urllib will fall out, and the category will be defined correctly.
Next: a very incomprehensible moment about img=content. As far as I understand, you directly take the picture itself (a set of bytes) and write it to the database? If so, then this is fundamentally wrong, ImageField works differently. First, in a database, this is a normal varying charfield. Secondly, it does not store the image content itself, but the file name under which the file was saved during upload. The file itself is stored elsewhere (by default, in the file system next to the directory specified in the MEDIA_ROOT setting) For example, if this field contains the value 'path/to/my/photo.jpg', then this means that when accessing .img.url (note that we are accessing the url attribute of the img field of the model_name model) will return something like /media/path/to/my/photo.jpg,
I advise you to rewrite the code.
  • Firstly, I strongly advise you to support PEP8 when making a design .
  • Secondly, as already recommended above, use requests .
  • Thirdly, use the shortcuts provided by Dzhanga. In this case, I'm talking about the render function instead of the HttpResponse(render_to_string) pair and the get_or_create() method on the model manager.
  • Get rid of code duplication
  • Don't use greedy excepts. Catch should be only those exceptions that can occur regularly in the course of work.

With the above in mind, your code might look something like this:
from django.shortcuts import render
import requests
import requests.exceptions as rex

def baza(request):
    # В этом месте мы скачали страничку по адресу BAZA_URL/
    try:
        page = requests.get("BAZA_URL")
        page.raise_for_status()

    # Попутно обработали ситуацию, если страница по каким-то причинам
    # недоступна (например, её переместили, сервер ушёл в даун или просто
    # сеть недоступна). Все остальные возможные ошибки мы в этом месте
    # не обрабатываем.

    except (rex.ConnectionError, rex.HTTPError) as ex:
        return HttpResponse("Unable to open BAZA_URL")

    baza = page.content.split('<br>')

    for line in page:
        # Здесь мы просто ввели локальные переменные для упрощения
        # кода. Согласитесь, когда в поле модели name нужно подставить
        # имя, то проще написать переменную name, чем высчитывать, какой
        # же это по счёту элемент массива :)
        #
        # К тому же, если вдруг формат данных изменится, код придётся
        # править только в одном месте. так что мы заодно избавились от
        # дублирования.
        cat_name, img_url, name, text, options = line.split('--')[:4]

        # Воспользовались шорткатом от Джанги. Модель будет взята из базы,
        # если на существует с таким именем. Если нет, то будет создана.
        # Тоже избавление от дублирования
        categories, created = Categories.objects.get_or_create(name=cat_name)

        # Создание модели Item с помощью метода create у менеджера. Сразу
        # же мы решаем здесь возможную проблему с сетью. Если какой-то файл
        # окажется недоступным, мы его не будем сохранять, а перейдём к
        # следующему

        try:
            pic = requests.get(img_url)
            pic.raise_for_status()

            Item.objects.create(categories=categories,
                                img=ContentFile(pic.content),
                                name=name,
                                text=text,
                                options=options)
        except (rex.ConnectionError, rex.HTTPError) as ex:
            # Пришлось немного продублировать код, потому что здесь
            # возможны те же ошибки, что и в самом начале вьюхи.
            continue
Some things I will deliberately omit (for example, the fact that for all HTTP requests with requests you can use one connection without creating a new one for each request)
And one more tip: operations that take a long time and which can fail for reasons beyond your control , it is better not to do it in a request-response cycle, but to put it into background processing. For example, use celery

R
Roman Kitaev, 2015-11-19
@deliro

I advise you to use a wrapper over urllib - requests.

# Вместо такой конструкции
Item(categories=categories, img=content, name=line[2], text=line[3], options=line[4]).save()
# Лучше использовать
Item.objects.create(categories=categories, img=content, name=line[2], text=line[3], options=line[4])

except without exception never use. There you need to write except Categories.DoesNotExist:
the General part do not duplicate. Take out in finally.
And what's wrong?

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question