
virtual QNetworkReply *handleRequest(QString path, QStringList sort, Pagination *pagination, QVariantMap filters = QVariantMap(), QStringList fields = QStringList(), QString id = 0)  QNetworkReply *JsonRestListModel::fetchMoreImpl(const QModelIndex &parent) { Q_UNUSED(parent) return apiInstance()->handleRequest(requests()->get(), sort(), pagination(), filters(), fields()); }  ... MyApi { id: myApi } JsonRestListModel { id: jsonSampleModel api: myApi //  API  idField: 'id' // -    //    API  handleRequest // ReadOnly    readOnly  get ( )  getDetails (   ) //  -  .  Requests requests { get: "/v1/coupon" getDetails: "/v1/coupon/{id}" } //    filters: {'isArchive': '0'} //    fields: ['id','title'] //  sort: ['-id'] //   pagination { policy: Pagination.PageNumber // -    perPage: 20 //-     } //         Component.onCompleted: { reload(); } } ...  [{ "id": 1, "sourceServiceId": 2, "categoryName": "", "categoryCode": "aktsii", "categoryIdentifier": "0", "parentCategoryIdentifier": "0", "categoryAdditionalInfo": "0", "isActive": 1 }, { "id": 2, "sourceServiceId": 2, "categoryName": "", "categoryCode": "kupony", "categoryIdentifier": "28", "parentCategoryIdentifier": "28", "categoryAdditionalInfo": "https://blizzard.kz/kuponator/categ/28", "isActive": 1 } , ...]  [{ "id": 1, "sourceServiceId": 1, "cityId": 1, "createTimestamp": "2015-03-12 14:01:57", "lastUpdateDateTime": "2016-10-20 03:54:47", "recordHash": "e7b01c1a69bc66e1f1a62d8fcb0825de", "title": "Home Club", "shortDescription": "    , , ,    ", "longDescription": "   –       .   ,    –   -  Home Club.           50%!      , ,    .   ! ", "conditions": " <p class="e-condition__text">:</p> <ul class="b-conditions-list"> <li class="e-condition">      -  Home Club.</li> <li class="e-condition"> <strong></strong>:  50%   - 1 500 .  3 000 .</li> <li class="e-condition">         ( ).</li> <li class="e-condition">      .</li> <li class="e-condition">    10 .</li> <li class="e-condition"> <strong>VIP-     .   VIP-     .</strong> </li> <li class="e-condition">        .</li> <li class="e-condition"> <strong>    :</strong><br> +7 (727) 308-23-63,<br> +7 (747) 841-42-51,<br> +7 (701) 985-90-72.</li> <li class="e-condition"> <strong>   .</strong> </li> <li class="e-condition">      2 ,     ( ).</li> <li class="e-condition">        ,       «».</li> <li class="e-condition">      Home Club  :  ,    ,  , Home Club.</li> <li class="e-condition">         ,   ,    .</li> <li class="e-condition"> <strong>     .</strong> </li> <li class="e-condition">    12  2015 . ().</li> <li class="e-condition"> <span hashstring="deal_refunds_policy" hashtype="content"> </span> </li> <li class="e-condition"> <span hashstring="deal_standard_conditions" hashtype="content"> </span> </li> </ul> <p class="e-offer__features"></p> <ul class="b-offer__features-list"> <li class="e-offer__feature ">  ,    ,  , Home Club </li> <li class="e-offer__feature "> :<br> +7 (727) 308-23-63<br>+7 (747) 841-42-51<br>+7 (701) 985-90-72<br> </li> <li class="e-offer__feature "> :<br> : </li> </ul>", "features": " <p class="e-offer__features">:</p> <ul class="b-offer__features-list"> <li class="e-offer__feature">Home Club            ,    ,     .</li> <li class="e-offer__feature"> ​   10  (5    5 Vip-).  Vip-      , , -, ,  .</li> <li class="e-offer__feature"> ​ Home Club    -  3- : <ul> <li> ;</li> <li>;</li> <li> .</li> </ul> </li> <li class="e-offer__feature"> ​  : <ul> <li> 4-  7-  ;</li> <li>1 :  , -, , ;</li> <li>2 : 2-  ,  ,    , ,   ;</li> <li>3 : 2  ,   .</li> </ul> </li> <li class="e-offer__feature"> ​VIP-: <ul> <li> 4-  11-  ;</li> <li>1 : ,    10 ,  , ,   , ,  ;</li> <li>2 : -12 ,  2-  4-   (    ), 2 ..</li> </ul> </li> <li class="e-offer__feature"> : <a data-seohide-href="/deal/away/20056/" class="e-offer__feature--link seohide-link" target="_blank" rel="nofollow" title="http://www.home-club.kz/">www.home-club.kz/</a> </li> </ul>", "imagesLinks": [ "https://static.chocolife.me/static/upload/images/deal/for_deal_page/21000/20056/660x305/1_20150312023051426147565.7364.jpg", "https://static.chocolife.me/static/upload/images/deal/for_deal_page/21000/20056/660x305/2_20150312023051426147565.9348.jpg", "https://static.chocolife.me/static/upload/images/deal/for_deal_page/21000/20056/660x305/4_20150312093171426174997.7985.jpg", "https://static.chocolife.me/static/upload/images/deal/for_deal_page/21000/20056/660x305/5_20150312093171426174997.944.jpg", "https://www.chocolife.me/" ], "timeToCompletion": null, "mainImageLink": "https://www.chocolife.me/", "originalCouponPrice": "30 000", "originalPrice": "30 000", "discountPercent": "-51%", "discountPrice": "18 000", "discountType": "full", "boughtCount": "1", "sourceServiceCategories": "1 , 82 , 8 , 2", "pageLink": "https://www.chocolife.me//20056-arenda-kottedzha-s-dvumya-spalnyami-gorki-sauna-darts-i-mnogoe-drugoe-v-prirodno-razvlekatelnom-parke-home-club-skidka-do-50", "isArchive": 1, "tryToUpdateCount": 0, "viewCount": "0", "serviceName": "Chocolife.me", "cityName": "" }, { "id": 2, "sourceServiceId": 1, "cityId": 1, "createTimestamp": "2015-03-12 14:01:57", "lastUpdateDateTime": "2016-11-01 12:39:53", "recordHash": "dce10232f1acb53b1ee7a8bf3902e0c0", "title": "    AquaBike Centre", "shortDescription": "       ", "longDescription": null, "conditions": null, "features": " <p class="e-offer__features">:</p> <ul class="b-offer__features-list"> <li class="e-offer__feature">        .     .</li> <li class="e-offer__feature"> Aquabike – : <ul> <li> ;</li> <li> ;</li> <li>  ;</li> <li>  ;</li> <li>  ;</li> <li>    ;</li> <li> ;</li> <li> .</li> </ul> </li> <li class="e-offer__feature"> <strong> :</strong> <ul> <li>    ;</li> <li>         ;</li> <li> ,  ;</li> <li>  ;</li> <li>   ,    ;</li> <li>  ,    ;</li> <li>   ;</li> <li>   , ,  .</li> </ul> </li> <li class="e-offer__feature"> <strong>     1    .</strong> </li> <li class="e-offer__feature">  AquaBike Centre  : <ul> <li>  ,   2 ;</li> <li>   ;</li> <li>,  45 .</li> </ul> </li> </ul>", "imagesLinks": [ "https://static.chocolife.me/static/upload/images/deal/for_deal_page/21000/20016/660x305/1_20150314013241426318344.7033.jpg", "https://static.chocolife.me/static/upload/images/deal/for_deal_page/21000/20016/660x305/2_20150314013241426318344.8157.JPG", "https://static.chocolife.me/static/upload/images/deal/for_deal_page/21000/20016/660x305/4_20150311053411426073981.6524.JPG", "https://www.chocolife.me/" ], "timeToCompletion": null, "mainImageLink": "https://www.chocolife.me/", "originalCouponPrice": "3 000", "originalPrice": "3 000", "discountPercent": "-50%", "discountPrice": "1 500", "discountType": "full", "boughtCount": "58", "sourceServiceCategories": "1 , 68 , 36 , 2", "pageLink": "https://www.chocolife.me//20016-novinka-iz-francii-vse-dlya-vashey-krasoty-zdorovya-i-relaksacii-trenirovki-po-akvabaykingu-a-takzhe-pressoterapiya-so-skidkoy-50-v-aquabike-centre", "isArchive": 1, "tryToUpdateCount": 0, "viewCount": "0", "serviceName": "Chocolife.me", "cityName": "" }, ...]  { "id": 1, "sourceServiceId": 1, "cityId": 1, "createTimestamp": "2015-03-12 14:01:57", "lastUpdateDateTime": "2016-10-20 03:54:47", "recordHash": "e7b01c1a69bc66e1f1a62d8fcb0825de", "title": "Home Club", "shortDescription": "    , , ,    ", "longDescription": "   –       .   ,    –   -  Home Club.           50%!      , ,    .   ! ", "conditions": " <p class="e-condition__text">:</p> <ul class="b-conditions-list"> <li class="e-condition">      -  Home Club.</li> <li class="e-condition"> <strong></strong>:  50%   - 1 500 .  3 000 .</li> <li class="e-condition">         ( ).</li> <li class="e-condition">      .</li> <li class="e-condition">    10 .</li> <li class="e-condition"> <strong>VIP-     .   VIP-     .</strong> </li> <li class="e-condition">        .</li> <li class="e-condition"> <strong>    :</strong><br> +7 (727) 308-23-63,<br> +7 (747) 841-42-51,<br> +7 (701) 985-90-72.</li> <li class="e-condition"> <strong>   .</strong> </li> <li class="e-condition">      2 ,     ( ).</li> <li class="e-condition">        ,       «».</li> <li class="e-condition">      Home Club  :  ,    ,  , Home Club.</li> <li class="e-condition">         ,   ,    .</li> <li class="e-condition"> <strong>     .</strong> </li> <li class="e-condition">    12  2015 . ().</li> <li class="e-condition"> <span hashstring="deal_refunds_policy" hashtype="content"> </span> </li> <li class="e-condition"> <span hashstring="deal_standard_conditions" hashtype="content"> </span> </li> </ul> <p class="e-offer__features"></p> <ul class="b-offer__features-list"> <li class="e-offer__feature ">  ,    ,  , Home Club </li> <li class="e-offer__feature "> :<br> +7 (727) 308-23-63<br>+7 (747) 841-42-51<br>+7 (701) 985-90-72<br> </li> <li class="e-offer__feature "> :<br> : </li> </ul>", "features": " <p class="e-offer__features">:</p> <ul class="b-offer__features-list"> <li class="e-offer__feature">Home Club            ,    ,     .</li> <li class="e-offer__feature"> ​   10  (5    5 Vip-).  Vip-      , , -, ,  .</li> <li class="e-offer__feature"> ​ Home Club    -  3- : <ul> <li> ;</li> <li>;</li> <li> .</li> </ul> </li> <li class="e-offer__feature"> ​  : <ul> <li> 4-  7-  ;</li> <li>1 :  , -, , ;</li> <li>2 : 2-  ,  ,    , ,   ;</li> <li>3 : 2  ,   .</li> </ul> </li> <li class="e-offer__feature"> ​VIP-: <ul> <li> 4-  11-  ;</li> <li>1 : ,    10 ,  , ,   , ,  ;</li> <li>2 : -12 ,  2-  4-   (    ), 2 ..</li> </ul> </li> <li class="e-offer__feature"> : <a data-seohide-href="/deal/away/20056/" class="e-offer__feature--link seohide-link" target="_blank" rel="nofollow" title="http://www.home-club.kz/">www.home-club.kz/</a> </li> </ul>", "imagesLinks": [ "https://static.chocolife.me/static/upload/images/deal/for_deal_page/21000/20056/660x305/1_20150312023051426147565.7364.jpg", "https://static.chocolife.me/static/upload/images/deal/for_deal_page/21000/20056/660x305/2_20150312023051426147565.9348.jpg", "https://static.chocolife.me/static/upload/images/deal/for_deal_page/21000/20056/660x305/4_20150312093171426174997.7985.jpg", "https://static.chocolife.me/static/upload/images/deal/for_deal_page/21000/20056/660x305/5_20150312093171426174997.944.jpg", "https://www.chocolife.me/" ], "timeToCompletion": null, "mainImageLink": "https://www.chocolife.me/", "originalCouponPrice": "30 000", "originalPrice": "30 000", "discountPercent": "-51%", "discountPrice": "18 000", "discountType": "full", "boughtCount": "1", "sourceServiceCategories": "1 , 82 , 8 , 2", "pageLink": "https://www.chocolife.me//20056-arenda-kottedzha-s-dvumya-spalnyami-gorki-sauna-darts-i-mnogoe-drugoe-v-prirodno-razvlekatelnom-parke-home-club-skidka-do-50", "isArchive": 1, "tryToUpdateCount": 0, "viewCount": "0", "serviceName": "Chocolife.me", "cityName": "" }  #ifndef SKIDKZAPI_H #define SKIDKZAPI_H #include "apibase.h" #include <QtQml> class SkidKZApi : public APIBase { Q_OBJECT public: Q_INVOKABLE explicit SkidKZApi(); // .      QML static void declareQML() { qmlRegisterType<SkidKZApi>("com.github.qtrestexample.skidkzapi", 1, 0, "SkidKZApi"); } //      ReadOnly  QNetworkReply *handleRequest(QString path, QStringList sort, Pagination *pagination, QVariantMap filters = QVariantMap(), QStringList fields = QStringList(), QString id = 0); //      /v1/coupon QNetworkReply *getCoupons(QStringList sort, Pagination *pagination, QVariantMap filters = QVariantMap(), QStringList fields = QStringList()); //      /v1/coupon/{id} QNetworkReply *getCouponDetail(QString id); //      /v1/categories QNetworkReply *getCategories(QStringList sort, Pagination *pagination); }; #endif // SKIDKZAPI_H  #include "skidkzapi.h" #include <QFile> #include <QTextStream> #include <QUrlQuery> SkidKZApi::SkidKZApi() : APIBase(0) { } QNetworkReply *SkidKZApi::handleRequest(QString path, QStringList sort, Pagination *pagination, QVariantMap filters, QStringList fields, QString id) { // ,           if (path == "/v1/coupon") { return getCoupons(sort, pagination, filters, fields); } else if (path == "/v1/coupon/{id}") { return getCouponDetail(id); } else if (path == "/v1/categories") { return getCategories(sort, pagination); } } //  ,   ,           QNetworkReply *SkidKZApi::getCoupons(QStringList sort, Pagination *pagination, QVariantMap filters, QStringList fields) { //   QUrl url = QUrl(baseUrl()+"/v1/coupon"); QUrlQuery query; // if (!sort.isEmpty()) { query.addQueryItem("sort", sort.join(",")); } //      switch(pagination->policy()) { case Pagination::PageNumber: query.addQueryItem("per-page", QString::number(pagination->perPage())); query.addQueryItem("page", QString::number(pagination->currentPage())); break; case Pagination::None: case Pagination::Infinity: case Pagination::LimitOffset: case Pagination::Cursor: default: break; } // .  ,     -    if (!filters.isEmpty()) { QMapIterator<QString, QVariant> i(filters); while (i.hasNext()) { i.next(); query.addQueryItem(i.key(), i.value().toString()); } } //       if (!fields.isEmpty()) { query.addQueryItem("fields", fields.join(",")); } //  url.setQuery(query.query()); //     GET QNetworkReply *reply = get(url); return reply; } //      QNetworkReply *SkidKZApi::getCouponDetail(QString id) { if (id.isEmpty()) { qDebug() << "ID is empty!"; return 0; } //         GET QUrl url = QUrl(baseUrl()+"/v1/coupon/"+id); QNetworkReply *reply = get(url); return reply; } //    ,   QNetworkReply *SkidKZApi::getCategories(QStringList sort, Pagination *pagination) { // QUrl url = QUrl(baseUrl()+"/v1/categories"); QUrlQuery query; // if (!sort.isEmpty()) { query.addQueryItem("sort", sort.join(",")); } // switch(pagination->policy()) { case Pagination::PageNumber: query.addQueryItem("per-page", QString::number(pagination->perPage())); query.addQueryItem("page", QString::number(pagination->currentPage())); break; case Pagination::None: case Pagination::Infinity: case Pagination::LimitOffset: case Pagination::Cursor: default: break; } url.setQuery(query.query()); QNetworkReply *reply = get(url); return reply; }  #ifndef COUPONMODEL_H #define COUPONMODEL_H #include "abstractjsonrestlistmodel.h" #include "api/skidkzapi.h" class CouponModel : public AbstractJsonRestListModel { Q_OBJECT public: explicit CouponModel(QObject *parent = 0); //   QML (    main.cpp   QML) static void declareQML() { AbstractJsonRestListModel::declareQML(); qmlRegisterType<CouponModel>("com.github.qtrestexample.coupons", 1, 0, "CouponModel"); } protected: //    API QNetworkReply *fetchMoreImpl(const QModelIndex &parent); QNetworkReply *fetchDetailImpl(QString id); //    QVariantMap preProcessItem(QVariantMap item); }; #endif // COUPONMODEL_H  #include "couponmodel.h" CouponModel::CouponModel(QObject *parent) : AbstractJsonRestListModel(parent) { } QNetworkReply *CouponModel::fetchMoreImpl(const QModelIndex &parent) { Q_UNUSED(parent) //   API  return static_cast<SkidKZApi *>(apiInstance())->getCoupons(sort(), pagination(), filters(), fields()); } QNetworkReply *CouponModel::fetchDetailImpl(QString id) { //   API  return static_cast<SkidKZApi *>(apiInstance())->getCouponDetail(id); } QVariantMap CouponModel::preProcessItem(QVariantMap item) { //      createTimestamp QDate date = QDateTime::fromString(item.value("createTimestamp").toString(), "yyyy-MM-dd hh:mm:ss").date(); item.insert("createDate", date.toString("dd.MM.yyyy")); //  -  originalCouponPrice QString originalCouponPrice = item.value("originalCouponPrice").toString().trimmed(); if (originalCouponPrice.isEmpty()) { originalCouponPrice = "?"; } QString discountPercent = item.value("discountPercent").toString().trimmed().remove("—").remove("-").remove("%"); if (discountPercent.isEmpty()) { discountPercent = "?"; } QString originalPrice = item.value("originalPrice").toString().trimmed(); if (originalPrice.isEmpty()) { originalPrice = "?"; } QString discountPrice = item.value("discountPrice").toString().remove(".").trimmed(); if (discountPrice.isEmpty()) { discountPrice = "?"; } //    discountString,     API QString discountType = item.value("discountType").toString(); QString discountString = tr("Undefined Type"); if (discountType == "freeCoupon" || discountType == "coupon") { discountString = tr("Coupon: %1. Discount: %2%").arg(originalCouponPrice).arg(discountPercent); } else if (discountType == "full") { discountString = tr("Cost: %1. Certificate: %2. Discount: %3%").arg(originalPrice).arg(discountPrice).arg(discountPercent); } item.insert("discountString", discountString); return item; }  ... import com.github.qtrestexample.skidkzapi 1.0 import com.github.qtrest.jsonrestlistmodel 1.0 import com.github.qtrest.pagination 1.0 import com.github.qtrest.requests 1.0 ... //API ,    ,   -  =) SkidKZApi { id: skidKZApi baseUrl: "http://api.skid.kz" authTokenHeader: "Authorization" authToken: "Bearer 8aef452ee3b32466209535b96d456b06" Component.onCompleted: console.log("completed!"); } // ,  ReadOnly  // ,            -     ,      JsonRestListModel { id: categoriesRestModel api: skidKZApi idField: 'id' requests { get: "/v1/categories" } sort: ['categoryName'] pagination { policy: Pagination.PageNumber perPage: 20 currentPageHeader: "X-Pagination-Current-Page" totalCountHeader: "X-Pagination-Total-Count" pageCountHeader: "X-Pagination-Page-Count" } Component.onCompleted: { console.log(pagination.perPage); reload(); } } //  CouponModel ,     requests, ..    fetchMoreImpl. CouponModel { id: coupons; api: skidKZApi filters: {'isArchive': '0'} idField: 'id' fields: ['id','title','sourceServiceId','imagesLinks', 'mainImageLink','pageLink','cityId','boughtCount', 'shortDescription','createTimestamp', 'serviceName', 'discountType', 'originalCouponPrice', 'originalPrice', 'discountPercent', 'discountPrice'] sort: ['-id'] pagination { policy: Pagination.PageNumber perPage: 20 currentPageHeader: "X-Pagination-Current-Page" totalCountHeader: "X-Pagination-Total-Count" pageCountHeader: "X-Pagination-Page-Count" } Component.onCompleted: { console.log(pagination.perPage); reload(); } } Source: https://habr.com/ru/post/314984/
All Articles