Связаться с нами

  • (097) ?601-88-87
    (067) ?493-44-27
    (096) ?830-00-01

Статьи

Django: Деревовидні коментарі.

  1. Постановка задачі
  2. Модель

Django

Вступ: Противників велосипедостроєнія прохання відразу піти сюди: django-threadedcomments або прокрутити до списку посилань на алгоритми в кінці статті. Досвідчені джанговоди також не знайдуть тут нічого цікавого.

Однією з найбільш важливих для мене фішок є деревовидні коментарі. Вони дозволяють легше стежити за ходом обговорення, що по-моєму дуже важливо. Їх відсутність або кривизна реалізації в open-source блог-двигунах стало однією з причин написати свій.

Постановка задачі

  • Відсутність реєстрації (навіщо мучити користувача? Будуть проблеми зі спамом - будемо думати).
  • Запам'ятовування даних коментатора в cookie.
  • Маркер авторитетного коментаря і коментаря автора. (При великій кількості коментарів особисто я завжди вишукую коментарі автора і інших авторитетних людей.)
  • Favicon сайту коментатора як його аватарки.
  • Вибірка всіх коментарів до статті одним запитом. Додавання не повинно перелопачувати всі коментарі.
  • Валідація, перегляд і додавання без перезавантаження сторінки. Коректна робота без JavaScript
  • PS. Не забути де-небудь використовувати Django :)

Для початку, реалізуємо всі на Django, потім прикрутимо JavaScript.

Модель

Модель коментаря:

class Comment (models.Model): article = models.ForeignKey (Article) parent = models.ForeignKey ( 'self', blank = True, null = True, related_name = 'child_set') author_name = models.CharField (max_length = 32) author_email = models.EmailField () author_url = models.URLField (blank = True) text = models.TextField () pub_date = models.DateTimeField ( 'date published', default = datetime.now) admin_comment = models.BooleanField (default = False )

Модель використовує стандартні поля Django. Деревовидних реалізується посиланням на батька.

Може бути користувача коштувало винести в окрему модель, але для простоти поки залишу так. Якщо потрібна реєстрація - можна використовувати стандартного користувача Django.

Придивившись трохи уважніше до реалізації стандартного поля URLField, я розумію, що воно мені не підходить: при валідації сервер запитує введений урл і дивиться, що відповідь не 404. Не хочу. Та й якщо у людини з сервером проблеми, що йому не можна написати коментар?

Однак валідація потрібна, щоб не виходили посилання виду http://dpp.su/blog/ivan.ivanovich.googlepages.com. З цього пишемо свій URLField:

class SimpleURLField (CharField): def pre_save (self, model_instance, add): url = getattr (model_instance, self.attname, '') if add and url and not url.startswith ( 'http: //'): url = ' http: //% s '% url setattr (model_instance, self.attname, url) return url return CharField.pre_save (self, model_instance, add)

Тепер прийшов час задуматися вибіркою коментарів з бази. Рекурсивні запити робити б дуже не хотілося. Хоча, як кажуть тут , Якщо прибрати рекурсию в збережену процедуру, то швидкість MySQL буде прийнятною. Може бути і так, але мені такий підхід не подобається.

Перед нами класична задача: зберігання деревовидних структур в БД . Але, все-таки, озброївшись здоровим (або не дуже) змістом, починаємо винаходити велосипед.

На БАШЕЄВ якраз сьогодні цитата дуже в тему: геніальну фразу зараз почув на семінарі по роботі з zend framework - "Можна не винаходити велосипед, а погнута вже існуючий"

Перша думка: якщо зберігати повний шлях до кореня, то правильна черговість коментарів досягається простий сортуванням по цьому полю. Однак це накладає обмеження на кількість коментарів і глибину дерева. Але давайте подивимося на це обмеження уважніше.

Якщо використовувати varchar (255) і описувати кожен вузол дерева трьома цифрами, то ми отримаємо вкладеність 85 і тисячу коментарів на кожному рівні. Якщо чотирма - 64 і 10000. Для не надто популярного ресурсу цілком вистачить.

Якщо пошукати інформацію в інеті можна помітити, що цей спосіб майже завжди пропонують першим. Просто і працює швидше за все. Але тільки в тому випадку, якщо нам не важливо обмеження цього методу. Спочатку я думав написати порівняння найбільш популярних методів, але почавши писати передумав: аж надто багато подібних порівнянь. Та й Django виявляється ні до чого.

Повернемося до запропонованого рішення. Якщо ідея раптом не зрозуміла, наведу приклад зберігання коментарів в табіце. коментарі:
Повернемося до запропонованого рішення
А ось як вони будуть зберігатися в базі:

Відсортувавши таблицю по полю path ми отримуємо список коментарів в потрібному нам порядку. Тепер потрібно написати функцію генеруючу значення поля path. Значення генерується дуже просто - береться значення батька і дописується id додається об'єкта.

path = ( '% s-% 03d'% (parent.path, self.id,)) [: 255]

Однак, при додаванні об'єкта ми не можемо дізнатися його id, що призведе до додаткового UPDATE доданого об'єкта після його збереження. Також необхідно задуматися про наступне: якщо використовувати id для генерації path, то ограніеченіе на кількість кометаріев при цьому методі виходить загальним для всього сайту. 10000 коментарів до статті - це багато, а до всього сайту - не дуже. Тому використовувати id при генерації шляху погано. Доведеться створити додаткову колонку в таблиці для зберігання відносного id.

Використовуючи підхід, пропонований Django ми повинні створити свій тип поля, успадкованих від базового поля моделі Django, і перекрить у нього функцію збереження. Отримуємо наступне:

class TreeOrderField (models.CharField): def pre_save (self, model_instance, add): if add: parent = (model_instance.parent or model_instance.article); if parent.seq <1000: parent.seq + = 1; parent.save (); else: # update all comments to use 4digit masks pass value = '% s% 03d'% (getattr (parent, self.attname, ''), parent.seq,) [: 255] setattr (model_instance, self.attname, value) return value return models.CharField.pre_save (self, model_instance, add)

Тут можна реалізувати по-різному, але позбутися від додаткового UPDATE не виходить ні в одному з випадків. В окремому випадку PostgreSQL напевно можна використовувати sequence і тоді ліщніх udate`ов не буде.

Для визначення відступу коментаря в дереві можна використовувати принцип побудови path:

@property def level (self): return max (0, len (self.path) / 3-1)

Таким чином ми отримали наступне рішення: приклад .
А випробувати працездатність продложенного методу можна: тут .

Про відображення і контролер коментарів на Django, а також про використання Ajax`а я розповім наступного разу (якщо хто-небудь попросить).

посилання:

  • django-threadedcomments - реалізація коментарів, що використовує рекурсію при виведенні.
  • django-mptt реалізація множинної моделі зберігання дерев в БД.

Навіщо мучити користувача?
Та й якщо у людини з сервером проблеми, що йому не можна написати коментар?

Новости

Все товары для праздника оптом купить
Как сделать правильный выбор в работе, бизнесе и жизни, о котором никогда не придется жалеть. Мы хотим рассказать вам об удивительной и очень простой технике 7 вопросов, которые позволят оценить ситуацию

Пиротехника своими руками в домашних
Самые лучшие полезные самоделки рунета! Как сделать самому, мастер-классы, фото, чертежи, инструкции, книги, видео. Главная САМОДЕЛКИ Дизайнерские

Фольгированные шары с гелием
Для начала давайте разберемся и чего же выполнен фольгированный шар и почему он летает дольше?! Как вы помните, наши латексные шарики достаточно пористые, поэтому их приходится обрабатывать специальным

Как сделать красивую снежинку из бумаги
Красивые бумажные снежинки станут хорошим украшением дома на Новый год. Они создадут в квартире атмосферу белоснежной, зимней сказки. Да и просто занимаясь вырезанием из бумаги снежинок разнообразной

Надувные шарики с гелием с доставкой
На праздники часто бывают востребованы воздушные шарики, надутые гелием. Обычно, их покупают уже готовыми (надутыми) и привозят на праздник. Или, приглашают специалистов, которые приезжают и надувают

Как сделать из бумаги самолет
 1. Самолеты сделанный по первой и второй схеме являются самыми распространенными. Собирается такое оригами своими руками достаточно быстро, несмотря на это самолет летит достаточно далеко за счет свое

Аниматоры на детские праздники в Зеленограде
Уж сколько раз твердили миру…Что готовиться ко дню рождения нужно заранее, а не бегать в предпраздничный день угорелой кошкой. Нельзя впихнуть в 24 часа дела, рассчитанные на недели. К празднику нужно

2400 наименований пиротехники
В последние десятилетия наша страна может похвастаться появлением нескольких десятков отечественных производителей, специализирующихся на выпуске пиротехники. Если вы сомневаетесь, какой фейерверк заказать,