Модераторы: korob2001, ginnie
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Постраничный вывод из базы данных на Perl, Организация постраничного вывода на Perl 
:(
    Опции темы
qweqwe
Дата 17.6.2009, 14:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 55
Регистрация: 31.1.2007

Репутация: нет
Всего: 0



Здравствуйте!
Хочу попросить помочь решить следующий вопрос, который у меня возник: Организация постраничного вывода на Perl из базы данных. (Поиском по Форуму пользовался, ничего похожего не нашел)
В интернете, сколько пересмотрел, находилось только организация постраничного вывода на PHP. У меня же возник вопрос организации такой вещи именно на Perl.
Сам я только недавно начал осваивать Perl, поэтому хотел бы попросить не писать ответы вроде "Используй Limit" или "используй тот или иной модуль", потому как хотел бы разобраться с данным вопросом. Поэтому было бы очень здорово, если бы ответы были не только сделай вот и так или вот так, а сопровождались вставками поправленного кода, для того, чтобы лучше разобраться в проблеме.

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

Немного о реализации: для примера берется база данных (FireBird), состоящая из двух столбцов. Необходимо их вывести. Из input'a идет запрос, по которому потом происходит поиск по бд и осуществляется вывод нужной информации. Полный вывод из базы данных я организовал, но если же записей будет, к примеру 1000, то будет не особо удобно их просматривать, в связи с этим я и организовываю постраничный вывод.
Ошибка скрипта в следующем:
Начальный вывод страницы правильный, выводится заданное кол-во записей, есть ссылки на следующую (активная) и предыдущую (не активная) страницы. Ошибка - при нажатии на ссылку "следующая" данные не отображаются (т.е. выводится пустая таблица, хотя должны выводится, к примеру оставшиеся данные, если записей 14, а вывод идет по 10 записей), и данная ссылка остается активной (соответственно ссылка "предыдущая" активной не становится).

Хотел бы попросить помочь мне в решении данной проблемы.
Благодарю.




Код

#!/usr/bin/perl

use strict;
use DBI;
use CGI qw /:standard/;
#use CGI::Carp qw (fatalsToBrowser);
use CGI::Cookie;

#-------------------------------------------------------------------------------
# ?????????? ? ?? Firebird
#-------------------------------------------------------------------------------
my $DB_HOST_IB = "localhost";
my $DB_USER_IB = "SYSDBA";
my $DB_PASSWD_IB = "masterkey";
my $DB_BASE_IB = "/tester/mb.fdb";
my $DB_CHARSET_IB = "WIN1251";
my $DB_DIAL_IB = 3;
our $dsn_IB ="DBI:InterBase:database=$DB_BASE_IB;host=$DB_HOST_IB;ib_charset=$DB_CHARSET_IB;ib_dialect=$DB_DIAL_IB";
our $dbh_IB = DBI->connect($dsn_IB,$DB_USER_IB,$DB_PASSWD_IB);
my $search = param('ser');

print header;

my $row = $dbh_IB->selectrow_arrayref("select count(*) from T2");
my $count = $row->[0];
my $Page_Size = 10;
my $first = 1;
my $last = $first + $Page_Size - 1;
$last = $count if $last > $count;
########
my $results = $dbh_IB->selectall_arrayref("select P1,P2 from T2 where P1='$search'");
print qq(<table border="1">);
for(my $i = $first; $i <= $last; $i++)
{
my $user = $results->[$i-1];
print qq(<tr>\n);
printf("%s%s\n", "<td>$user->[0]</td>", "<td>$user->[1]</td>");
print qq(</tr>);
}
print qq(</table>);
########
my $prev_rec = $first - $Page_Size;
$prev_rec = 1 if $prev_rec < 1;
my $prev_link = sprintf('%s/%d', url(-full => 1), $prev_rec);
my $next_rec = $last + 1;
my $next_link = sprintf('%s/%d', url(-full => 1), $next_rec);
if ($first = 1)
{
print 'Previous';
}
else
{
printf('<a href="%s">Previous</a>', $prev_link);
}
############
print " | ";
############
if ($next_rec < $count)
{
printf('<a href="%s">Next</a>', $next_link);
}
else
{
print 'Next';
}
###############


PM MAIL   Вверх
ginnie
Дата 17.6.2009, 14:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Комодератор
Сообщений: 1287
Регистрация: 6.1.2008
Где: Москва

Репутация: 4
Всего: 49



qweqwe, опишите по-русски алгоритм работы Вашего скрипта.

P.S. Используйте шаблонизатор (например, HTML::Template), т.к. вставлять HTML в код скрипта сейчас не модно.

Это сообщение отредактировал(а) ginnie - 17.6.2009, 14:39


--------------------
Написать код, понятный компьютеру, может каждый, но только хорошие программисты пишут код, понятный людям. (Мартин Фаулер. Рефакторинг)
PM MAIL Skype Jabber   Вверх
qweqwe
Дата 17.6.2009, 18:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 55
Регистрация: 31.1.2007

Репутация: нет
Всего: 0



ginnie, алгоритм следующий:
Имеется база данных, для примера возмем базу данных, состоящую из двух столбцов.
Данные будут выводится, по запросу select P1,P2 from T2 where P1='$search', где
my $search = param('ser') - данные для поиска.
Проблема в том, как осуществить потсраничный вывод этих данных на Perl.
Допустим, по запросу нашлось 1000 записей, необходимо выводить по 20 записей на страницу. Снизу будут идти ссылки на другие записи (к примеру 1-20 - 21-40 - 41-60 ...), т.е. элементарный постраничный вывод, который организован на многих сайтах и форумах.

Я хотел бы, чтобы вы помогли мне с доработкой скрипта, где что лучше дописать, либо показали, как вы видите организацию постраничного вывода.

P.S. Благодарю, ознакомлюсь с HTML::Template.


PM MAIL   Вверх
gcc
Дата 17.6.2009, 18:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Агент алкомафии
****


Профиль
Группа: Участник
Сообщений: 2691
Регистрация: 25.4.2008
Где: %&й

Репутация: 2
Всего: 17



почему не использовать лимит?
PM WWW ICQ Skype GTalk Jabber   Вверх
KSURi
Дата 17.6.2009, 18:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 887
Регистрация: 8.6.2006
Где: Russia

Репутация: 2
Всего: 27



Простейший постраничный вывод я бы сделал так:
pager.cgi
Код

#!perl

use HTML::Template;
use CGI qw(:standard);

# имитация загрузки данных из базы
my %data       = map { $_, {id => $_, data => time ^ $_} } 0 .. 42;
my $total_data = scalar keys %data;

# позволим пользователю выбирать кол-во записей на страницу (можно в куки засунуть)
my $default_per_page = 20;
my $per_page = int url_param('per_page') || $default_per_page;
my $offset   = int url_param('offset')   || 0;
# вывести последнюю страницу, на случай, если у кого ручки шаловливые окажутся)
$per_page = $default_per_page       if $per_page > $total_data;
$offset   = $total_data - $per_page if $offset   > $total_data;

# сюда будут выбраны записи для отображения (от текущего смещения до текущеего смещения + кол-во записей на страницу)
my $tmpl_data  = [];
for($offset .. $offset + $per_page) {
    last unless defined $data{$_}; # на случай, если записей осталось меньше, чем выводится на страницу
    push @$tmpl_data, delete $data{$_}
}

# признак наличия следующей страницы: текущее смещение + кол-во записей на страницу должно быть меньше общего кол-ва записей
my $has_next  = ($offset + $per_page) < $total_data;
my $next_page = $has_next ? $offset + $per_page : '';

# признак наличия предыдущей страницы: смещение больше нуля (т.е. мы не в начале)
my $has_prev  = $offset > 0;
my $prev_page = $has_prev ? $offset - $per_page : '';

# запишем сюда все страницы для того, чтобы можно было перескакивать на любую страницу
# page - номер страницы (+1 для того, чтобы нумерация не начиналась с нуля)
# offset = кол-во записей на страницу * на номер текущей страницы
# per_page надо указывать для того, чтобы сохранялось нестандартное значение
my $all_pages = [
    map +{page => $_+1, offset => $per_page*$_, per_page => $per_page},
         0 .. int($total_data / $per_page) # кол-во страниц = общее число записей / кол-во записей на страницу
];

my $tmpl = HTML::Template->new(filename => 'pager.html');
$tmpl->param(
    tmpl_data => $tmpl_data,
    all_pages => $all_pages,
    has_next  => $has_next,
    next_page => $next_page,
    has_prev  => $has_prev,
    prev_page => $prev_page,
    per_page  => $per_page,
);

print header(), $tmpl->output

pager.html:
Код

<html>
<body>

<table border="1">
<TMPL_LOOP NAME="tmpl_data">
    <tr>
        <td><TMPL_VAR NAME="id"></td>
        <td><TMPL_VAR NAME="data"></td>
    </tr>
</TMPL_LOOP>
</table>
<br>
<TMPL_IF NAME="has_prev">
    <a href='?offset=<TMPL_VAR NAME="prev_page">&per_page=<TMPL_VAR NAME="per_page">'>&lt;&lt;&nbsp;Previous</a>&nbsp;
</TMPL_IF>
<TMPL_LOOP NAME="all_pages">
    <a href='?offset=<TMPL_VAR NAME="offset">&per_page=<TMPL_VAR NAME="per_page">'><TMPL_VAR NAME="page"></a>
</TMPL_LOOP>
<TMPL_IF NAME="has_next">
    &nbsp;<a href='?offset=<TMPL_VAR NAME="next_page">&per_page=<TMPL_VAR NAME="per_page">'>Next&nbsp;&gt;&gt;</a>
</TMPL_IF>

</body>
</html>


Тут есть что допилить: при большом кол-ве страниц их лучше ограничивать (показывать, например, три предыдущих и три следующих), нет выделения текущей страницы (HTML::Template без заморочек не позволяет такое сделать).
Ну и конечно надо иметь ввиду, что такая навигация по страницам будет каждый раз заново выполнять поисковый запрос, со всеми вытекающими.


--------------------
Died at Life.pl line 21
PM Jabber   Вверх
ginnie
Дата 17.6.2009, 18:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Комодератор
Сообщений: 1287
Регистрация: 6.1.2008
Где: Москва

Репутация: 4
Всего: 49



qweqwe, я просил написать алгоритм работы Вашего скрипта, а не страничной навигации, как Вы ее себе представляете. Просто напишите, что по-вашему делает Ваш скрипт, типа
1. получаем из базы количество строк в таблице
2. задаем количество результатов на странице
3. определяем номер начального результата
4. определяем номер конечного результата, он не должен быть больше количества строк таблицы
...

Добавлено через 7 минут и 46 секунд
Цитата(KSURi @  17.6.2009,  18:21 Найти цитируемый пост)
нет выделения текущей страницы (HTML::Template без заморочек не позволяет такое сделать)

KSURi, не надо обижать HTML::Template, лучше написать "я в HTML::Template без заморочек такое сделать не могу"  smile 

Это сообщение отредактировал(а) ginnie - 17.6.2009, 18:29


--------------------
Написать код, понятный компьютеру, может каждый, но только хорошие программисты пишут код, понятный людям. (Мартин Фаулер. Рефакторинг)
PM MAIL Skype Jabber   Вверх
KSURi
Дата 17.6.2009, 21:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 887
Регистрация: 8.6.2006
Где: Russia

Репутация: 2
Всего: 27



Цитата(ginnie @  17.6.2009,  18:26 Найти цитируемый пост)
KSURi, не надо обижать HTML::Template, лучше написать "я в HTML::Template без заморочек такое сделать не могу"  smile 

Я это и имел ввиду, в принципе)

Добавлено через 7 минут и 20 секунд
Кстати, интересно посмотреть на пример реализации без заморочек.
Пробежался щас по документации HTML::Template и, честно говоря, не пришло мне в голову решение... ginnie, это правда можно полностью в шаблоне сделать?


--------------------
Died at Life.pl line 21
PM Jabber   Вверх
ginnie
Дата 18.6.2009, 11:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Комодератор
Сообщений: 1287
Регистрация: 6.1.2008
Где: Москва

Репутация: 4
Всего: 49



Цитата(KSURi @  17.6.2009,  21:29 Найти цитируемый пост)
ginnie, это правда можно полностью в шаблоне сделать?

Опиши, что ты подразумеваешь под выделением текущей страницы. Подумаем, как можно сделать.


--------------------
Написать код, понятный компьютеру, может каждый, но только хорошие программисты пишут код, понятный людям. (Мартин Фаулер. Рефакторинг)
PM MAIL Skype Jabber   Вверх
KSURi
Дата 18.6.2009, 11:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 887
Регистрация: 8.6.2006
Где: Russia

Репутация: 2
Всего: 27



Как минимум - сделать ее неактивной (не ссылкой) и выделенной другим цветом в перечислении всех страниц.

В ТТ можно было бы изобразить так:
Код

[% FOREACH page IN all_pages %]
    [% IF page.page == curr_page %]
        <b>[% page.page %]</b> <!-- curr_page = offset / per_page -->
    [% ELSE %]
        <a href="?offset=[% page.offset %]&per_page=[% page.per_page %]">[% page.page %]</a>
    [% END %]
[% END %]

Аналогично в Mason.

Это сообщение отредактировал(а) KSURi - 18.6.2009, 11:37


--------------------
Died at Life.pl line 21
PM Jabber   Вверх
xoma
Дата 18.6.2009, 11:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 86
Регистрация: 4.4.2007

Репутация: нет
Всего: нет



 а вот мой вариант пейджер, похожий на хабрахабровский....


Код

# $count   - общее кол-во записей
# $perPage - записей на странице
# $curPage - текущая (активная)  страничка
# $link    - ссылка, которая будет подставляться (пример "show/page/%d") - вместо %d - подставится номер страницы

sub Habra_pager{
    
      my $count    = int(shift);
      my $perPage  = int(shift);
      my $curPage  = int(shift);
      my $link     = shift;
      
      my $linkCount = $count / $perPage;
      my $start = $curPage - 4;
      $start    = 1 if ($start <= 0);
      my $stop  = $curPage + 4;
      $stop     = $linkCount if ($stop > $linkCount);
      
      my $out = '<ul class="pageList">';
      # ссылка на первые элементы списка
      $out.= "<li><a href='".sprintf($link,1)."'><---</a></li>" if ($start > 1);
      for(my $i = $start; $i <= $stop; $i++){
            my $displayLink = "<a href='".sprintf($link,$i)."'>$i</a>";
            # выделить текущую страницу
            if($i == $curPage){
               $out.= "<li class='activePageLink'>$displayLink</li>";
            }else{
               $out.= "<li>$displayLink</li>";
            }
      }
      # ссылка "далее" на последний элемент списка
      $out .="<li><a href='".sprintf($link,$linkCount)."'>---></li>" if($stop < $linkCount);
      $out .= '</ul>';      
      return $out;      
}



Это сообщение отредактировал(а) xoma - 18.6.2009, 11:58
PM MAIL WWW   Вверх
ginnie
Дата 18.6.2009, 14:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Комодератор
Сообщений: 1287
Регистрация: 6.1.2008
Где: Москва

Репутация: 4
Всего: 49



KSURi, для исходных данных

Код

{
    pages => [
        { number => 1, is_current => 0, url => '/page/1' },
        { number => 2, is_current => 1, url => '/page/2' },
        { number => 3, is_current => 0, url => '/page/3' },
    ],
}



Код

<TMPL_LOOP NAME="pages">
      <TMPL_IF NAME="is_current">
          <b><TMPL_VAR NAME="number"></b>
      <TMPL_ELSE>
          <a href="<TMPL_VAR NAME="url">"><TMPL_VAR NAME="number"></a>
      </TMPL_IF>
 </TMPL_LOOP>


P.S. в твоем первоначальном сообщении не обратил внимание на полностью в шаблоне сделать. Действительно полностью в шаблоне сделать нельзя, но писать, что для реализации этого функционала нужны "заморочки" я бы не стал.

Это сообщение отредактировал(а) ginnie - 18.6.2009, 14:20


--------------------
Написать код, понятный компьютеру, может каждый, но только хорошие программисты пишут код, понятный людям. (Мартин Фаулер. Рефакторинг)
PM MAIL Skype Jabber   Вверх
Ramirez
Дата 18.6.2009, 14:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 305
Регистрация: 18.1.2005
Где: Moscow, ExUSSR

Репутация: 1
Всего: 5



полностью в шаблоне можно, но потребуются расширения, позволяющие выполнять простейшие операции с переменными в шаблоне, например http://search.cpan.org/~samtregar/HTML-Tem...pr-0.07/Expr.pm



Это сообщение отредактировал(а) Ramirez - 18.6.2009, 15:00
PM ICQ   Вверх
qweqwe
Дата 18.6.2009, 22:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 55
Регистрация: 31.1.2007

Репутация: нет
Всего: 0



Благодарю всех за помощь. smile  Буду разбираться.  smile 
PM MAIL   Вверх
gcc
Дата 2.8.2009, 08:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Агент алкомафии
****


Профиль
Группа: Участник
Сообщений: 2691
Регистрация: 25.4.2008
Где: %&й

Репутация: 2
Всего: 17



а как сделать ссылку именно на пост? при постраничном выводе

то есть так как эта с виду:
_http://forum.vingrad.ru/index.php?showtopic=258166&view=findpost&p=1861021

если я хочу ссылатся на какое-то сообщение
PM WWW ICQ Skype GTalk Jabber   Вверх
gcc
Дата 13.8.2009, 09:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Агент алкомафии
****


Профиль
Группа: Участник
Сообщений: 2691
Регистрация: 25.4.2008
Где: %&й

Репутация: 2
Всего: 17



что-то я туплю или не понял, но а как узнать страницу на которой должен быть конкретный iD?

у меня на страницах по 10 элементов.

Код

$all = SELECT count(*) from topic
$page_to = SELECT count(*) from topic where id <= 0


как тут сделать?
Код

$topoc = $page_to / $all;


я нахожусь на странице 4, всего страниц 12, допустим

на странице 4 я редактирую/или удаляю сообщение, и как мне после редактирования вернутся назад на страницу 4? 


Это сообщение отредактировал(а) gcc - 13.8.2009, 09:40
PM WWW ICQ Skype GTalk Jabber   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Perl: CGI программирование"
korob2001
sharq
  • В этом разделе обсуждаются вопросы относящиеся только к CGI программированию
  • Если ваш вопрос не относится к системному или CGI программированию, задавайте его в общем разделе
  • Если ваш вопрос относится к системному программированию, задавайте его здесь
  • Интерпретатор Perl можно скачать здесь ActiveState, O'REILLY, The source for Perl
  • Справочное руководство "Установка perl-модулей", качать здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, korob2001, sharq.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Perl: разработка для Web | Следующая тема »


 




[ Время генерации скрипта: 0.0578 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.