Найти - Пользователи
Полная версия: [РЕШЕНО] После долгого импортирования в БД (в чистую базу успешно заливаются более 4700 записей), возникает ошибка KeyError: 'address'
Начало » Django » [РЕШЕНО] После долгого импортирования в БД (в чистую базу успешно заливаются более 4700 записей), возникает ошибка KeyError: 'address'
1
TitanFighter
Добрый день.

Целый вечер уже бьюсь над ошибкой. Помогите пожалуйста кто чем может решить ее.
Парсю данные и заливаю их в БД.

### часть кода из 1го метода, который завершается формированием словаря
                basic_dict[self.country][city.text.lstrip()][name] = dict(detailed_url=detailed_url,
                                                                        place_type = self.place_type)
### тут 2ой метод, который завершается расширением первого словаря
                            extended_dict[self.country][city][cinema].update(dict(address = street1,
                                                                            phone_number = phone1,
                                                                            official_website = website1))
        self.showtime(extended_dict)
### тут 3ий метод, который принимает расширенный словарь и начинает уже парсить данные и заливать в БД.
    def showtime(self, extended_dict):
        showtime_dict = extended_dict
        for city in showtime_dict[self.country]:
            for cinema in showtime_dict[self.country][city]:
                url = showtime_dict[self.country][city][cinema]['detailed_url']
                showtimes_tab_url = '/showtimes/#!=&cinema-section=%2Fshowtimes%2F'
                tree = prepare_content(url + showtimes_tab_url)
                for film in tree.xpath('//div[@class="content"]'):
                    film_name = film.xpath('.//a[@class="navi"]/text()')[0]
                    for date in film.xpath('.//li[contains(@class,"showtimes-day sdt")]'):
                        film_date = date.xpath('.//div[@class="date"]/text()')[0]
                        for time in date.xpath('.//ul[@class="showtimes-day-block"]/li'):
                            film_time = time.xpath('string(a/text())')
                            film_buy_ticket_url = time.xpath('string(a/@href)')
                            if len(film_time) == 0:
                                film_time = None
                            is_3d = time.find('span')
                            film_format = ''
                            if film_time is not None:
                                if is_3d is not None:
                                    film_format = '3D'
                                else:
                                    film_format = '2D'
                                # IMPORT
                                from app_places.models import Place
                                from app_shows_and_times.models import Show, Showtime
                                get_showtime_place = Place.objects.get(place_name = cinema, place_street = showtime_dict[self.country][city][cinema]['address'])
                                get_showtime_show = Show.objects.get(show_name = film_name)
                                showtime = Showtime.objects.create(
                                                                showtime_dates = film_date,
                                                                showtime_times = film_time,
                                                                showtime_format = film_format,
                                                                showtime_buy_ticket_url = film_buy_ticket_url,
                                                                showtime_place = get_showtime_place,
                                                                showtime_show = get_showtime_show)

Часть модели (и так уже кода много), где можно увидеть, что 2 поля идут как уникальные.
class Place(models.Model):
    place_name = models.CharField(max_length = 50, db_index = True)
    place_street = models.CharField(max_length = 80)
    place_phone = models.CharField(max_length = 60)
    place_official_site = models.URLField(max_length = 255, blank = True)
    place_country = models.ForeignKey(Country)
    place_city = models.ForeignKey(City)
    place_type = models.ForeignKey(PlaceType)
    class Meta:
        db_table = 'place'
        unique_together = (('place_name', 'place_street'))

Проблема. Запускаю класс, пошел импорт, который заканчивается KeyError: ‘address’, при том что 4700 записей в БД уже создано (базу предварительно очищаю), значит, как я понимаю, до какого-то этапа данное выражение:
get_showtime_place = Place.objects.get(place_name = cinema, place_street = showtime_dict)
работает. Но никак не могу понять, откуда возникает сбой.

Соответственно 3 вопроса:
1) Правильно ли я использую unique? Т.е. в модели задал в мета классе, а в objects.get указываю оба эти поля. Так и нужно?
2) Нужно ли для place_street = models.CharField(max_length = 80) делать db_index = True?
3) По какой причине может идти заливка в БД со ссылкой на ‘address’ в словаре, и в итоге выдавать ошибку?
Как одно из предположений, возможно 4700 записи и должно быть, но я тогда не понимаю, почему процесс заканчивается ошибкой.

Простите за кучу кода.

Едит1:
Думал уже, может где-то в базе Place нету записи street. Проверил - улицы везде указаны.
JOHN_16
TitanFighter
Всегда указывайте полный traceback ошибки, т.е. полный вывод

В extended_dict в какой то момент нету такого ключа. Если у вас стопориться процесс при 4700 записи, посмотрите что будет происходить при итерации 4701, скорее всего просто одна запись не обрабатывается должным образом.
JOHN_16
И еще , есть такая штука PEP8, если не слышали - то пролистайте, ознакомьтесь. Я к тому что комментарии у вас какие то странные, да и и импорт принято в начале файла указывать (есть конечно случаи когда можно по другому поступать, но это не тот)
TitanFighter
Выкладываю трейсбек. Буду знать на следующий раз, что нужно полный. Спасибо.
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/home/antonio/projects/idemvdvoem.com/idemvdvoem.com/src/shared/parser_to_db.py", line 23, in __init__
    self.basic_cinemas_info()
  File "/home/antonio/projects/idemvdvoem.com/idemvdvoem.com/src/shared/parser_to_db.py", line 176, in basic_cinemas_info
    self.detailed_cinemas_info(basic_dict)
  File "/home/antonio/projects/idemvdvoem.com/idemvdvoem.com/src/shared/parser_to_db.py", line 225, in detailed_cinemas_info
    self.showtime(extended_dict)
  File "/home/antonio/projects/idemvdvoem.com/idemvdvoem.com/src/shared/parser_to_db.py", line 271, in showtime
    get_showtime_place = Place.objects.get(place_name = cinema, place_street = showtime_dict[self.country][city][cinema]['address'])
KeyError: 'address'

Касательно проверить 4701 запись. 4700 записей - это сеансы в кинотеатрах. Сам словарь extended_dict не хранит всю эту тучу записей. Данные, которые собираются на протяжении 2х методов, которые непосредственно хранятся в extended_dict - это инфа о 64х кинотеатрах (адрес, тел) + ссылка на страницу расписания каждого кинотеатра. Это все заливается в базу (всего 64 объекта с максимум 10 столбиками) и только потом в 3ем методе подставляя эту ссылку на расписание, начинается вытягивание даты, времени, формата и тд с сайта и идет запись в БД. Так что, как я понимаю, тут не получиться попробовать получить 4701ый объект.

Про импорт и комментарии: первые 3 - это я описал для поста. Про коммент #IMPORT и про место самого импорта я знаю - это временно пометить себе, чтоб легче было находить глазами (черновой вариант вообщем. В чистовике все чисто ) Но все равно спасибо за внимание, ведь мог и не знать.
TitanFighter
Только лег в кровать, пришло озарение, как можно найти проблему.
У меня есть модель Showtimes, которая связана через FK с Places.
1 кинотеатр с адресом ул. Лаврухина, 4. ТЦ “РайON” вообще не проимпортировался в Places. Подумал, что может скобки. Проверил - .replace('“', “'”).replace('”', “'”).replace('“', ”'") - не помогло.
Может проблема в кириллице+латинице в названии?
Может как то unique_together влияет? У меня postgreSQL

Может теперь будет кому-то легче подсказать, куда мне ковырять?
FishHook
Да при чем тут unique_together? У вас же не при обращениях к БД ошибка, а в алгоритме, вот тут
showtime_dict[self.country][city][cinema]['address']
KeyError: ‘address’ означает, что в словаре, который вы получили
showtime_dict[self.country][city][cinema]
нет ключа address.
У тут вообще не при чем ни постгресс, ни индексы в нём, ни количество записей в базе, а имеет значение лишь то, что где-то выше вы неправильно создали словарь.
i.slepov
Чтобы не было ошибок “KeyError” используйте метод словаря get.

Вместо:
showtime_dict[self.country][city][cinema]['address']

Нужно:

showtime_dict[self.country][city][cinema].get('address', ' ')
TitanFighter
FishHook
Да при чем тут unique_together? У вас же не при обращениях к БД ошибка, а в алгоритме, вот тут
showtime_dict
KeyError: ‘address’ означает, что в словаре, который вы получили
showtime_dict
нет ключа address.
У тут вообще не при чем ни постгресс, ни индексы в нём, ни количество записей в базе, а имеет значение лишь то, что где-то выше вы неправильно создали словарь.
В 4 ночи уже ничего не хочется, кроме как обнять подушку . Утром прочитав ваши мысли, на свежую голову, я полностью с вами был согласен.
____
i.slepov
Чтобы не было ошибок “KeyError” используйте метод словаря get.
Вместо:
showtime_dict

Нужно:
showtime_dict.get('address', ‘ ’)
Я думал так сделать, но это был бы костыль в том смысле, что данные по нему вообще бы просто пропускались, так как данный кинотеатр даже не заливался в БД (не говоря уже о сеансах, из-за чего и создал этот топик).
____

А проблему таки решил. Оказалось, что при парсинге для одного кинотеатра не оказалось информации об официальном веб-сайте (вот млин для 64 есть, а для 1го нету ). Так как я проверку полей не делал, то в словарь не добавлялись данные cinema_street, cinema_phone, cinema_website для этого одного кинотеатра. Нету данных -> ошибка.

Мой код без проверки наличия данных на сайте:

    for city in extended_dict[country]:
        for cinema in extended_dict[country][city]:
            url = extended_dict[country][city][cinema]['detailed_url']
            tree = prepare(url)
    
            for street in tree.xpath(".//div[@class='address']"):
                cinema_street = street.xpath("text()")[0].strip()
    
                for phone in tree.xpath(".//div[@class='phone']"):
                    cinema_phone = phone.xpath("text()")[0].replace('Телефон:', '').strip()
                    
                    for website in tree.xpath(".//div[@class='website']/a"):
                        cinema_website = website.xpath("@href")[0].strip()
    
                        extended_dict[country][city][cinema].update(dict(address = cinema_street,
                                                                        phone_number = cinema_phone,
                                                                        official_website = cinema_website))

Итог: Нужно всегда делать проверку данных
Всем спасибо.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB