Даже если закрыть глаза на оформление кода, постоянное дублирование, то это всё равно очень странный код с неопределённым поведением. И вот почему:
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
Первым делом хочу обратить внимание на строку с комментарием "Метка 4". Вы, насколько я понял, хотите создать модель Categories, если её не нашлось в строке "Метка 1". Создать-то Вы её создали, но не сохранили! В базе такого объекта нет. Поэтому при вызове сохранения Item (см. "Метка 5") Вы можете схватить ошибку.
А можете не схватить, потому что возможна другая ситуация, когда категория (см. "Метка 1") нашлась, но картинка для скачивания определилась неправильно, и скачивание сломалось. Или просто сеть недоступна. В этом случае вывалится urllib, а категория будет определена правильно.
Далее: очень непонятный момент про img=content. Насколько я понял, Вы прямо берёте саму картинку (набор байт) и пишете его в БД? Если да, то это в корне неверно, ImageField работает по-другому. Во-первых, в базе данных это обычный varying charfield. Во-вторых, он хранит не сам контент картинки, а имя файла, под которым файл был сохранён при аплоаде. Сам файл хранится в другом месте (по умолчанию — в файловой системе рядышком в директории, указанной в настройке MEDIA_ROOT) Например, если в таком поле записано значение 'path/to/my/photo.jpg', то это значит, что при обращении model_name.img.url (обратите внимание, что мы обращаемся к атрибуту url поля img модели model_name) будет возвращено что-то типа /media/path/to/my/photo.jpg, где /media/ — корень хранилища загружаемых файлов (по умолчанию задаётся в настройке MEDIA_URL и имеет значение "/media/").
Советую переписать код.
- Во-первых, при оформлении настоятельно советую поддерживаться PEP8.
- Во-вторых, как уже рекомендовали выше, использовать requests.
- В-третьих, использовать шорткаты, которые предоставляются Джангой. В данном случае я говорю про функцию render вместо пары HttpResponse(render_to_string) и метод get_or_create() у менеджера модели.
- Избавиться от дублирования кода
- Не использовать жадные except'ы. Ловить следует только те исключения, которые могут возникнуть штатно в процессе работы.
С учётом вышеизложенного, Ваш код может выглядеть как-то так:
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
Некоторые вещи я намеренно опустим (например то, что для всех HTTP-запросов с помощью requests можно использовать одно соединение, не создавая новое для каждого запроса)
И ещё один совет: операции, которые выполняются длительное время и которые могут свалиться по независящим от Вас причинам, лучше не делать в цикле запроса-ответа, а вынести в фоновую обработку. Например, воспользоваться
celery