def _datalist(self, r, **attr):
        """
            Get a data list

            @param r: the S3Request
            @param attr: parameters for the method handler
        """

        # Check permission to read in this table
        authorised = self._permitted()
        if not authorised:
            r.unauthorised()

        resource = self.resource
        get_config = resource.get_config
        get_vars = self.request.get_vars

        # Get table-specific parameters
        layout = get_config("list_layout", None)

        # List ID
        list_id = get_vars.get("list_id",
                               attr.get("list_id", "datalist"))

        # List fields
        if hasattr(layout, "list_fields"):
            list_fields = layout.list_fields
        else:
            list_fields = resource.list_fields()

        # Default orderby
        orderby = get_config("list_orderby",
                             get_config("orderby", None))
        if orderby is None:
            if "created_on" in resource.fields:
                default_orderby = ~(resource.table["created_on"])
            else:
                for f in list_fields:
                    rfield = resource.resolve_selector(f)
                    if rfield.field and rfield.colname != str(resource._id):
                        default_orderby = rfield.field
                        break
        else:
            default_orderby = None

        # Pagination
        response = current.response
        s3 = response.s3

        # Pagelength = number of items per page
        if "dl_pagelength" in attr:
            pagelength = attr["dl_pagelength"]
        elif s3.dl_pagelength:
            pagelength = s3.dl_pagelength
        else:
            pagelength = 10

        # Rowsize = number of items per row
        if "dl_rowsize" in attr:
            rowsize = attr["dl_rowsize"]
        elif s3.dl_rowsize:
            rowsize = s3.dl_rowsize
        else:
            rowsize = 1

        # Make sure that pagelength is a multiple of rowsize
        if pagelength % rowsize:
            pagelength = (int(pagelength / rowsize) + 1) * rowsize

        record_id = get_vars.get("record", None)
        if record_id is not None:
            # Ajax-reload of a single record
            from s3query import FS
            resource.add_filter(FS("id") == record_id)
            start = 0
            limit = 1
        else:
            start, limit = self._limits(get_vars)

        # Initialize output
        output = {}

        # Prepare data list
        representation = r.representation

        # Ajax-delete items?
        if representation == "dl" and r.http in ("DELETE", "POST"):
            if "delete" in get_vars:
                return {"item": self._dl_ajax_delete(r, resource)}
            else:
                r.error(405, current.ERROR.BAD_METHOD)

        if representation in ("html", "dl", "popup"):

            # Retrieve the data
            if limit:
                initial_limit = min(limit, pagelength)
            else:
                initial_limit = pagelength

            # We don't have client-side sorting yet to override
            # default-orderby, so fall back unconditionally here:
            if not orderby:
                orderby = default_orderby

            datalist, numrows, ids = resource.datalist(fields=list_fields,
                                                       start=start,
                                                       limit=initial_limit,
                                                       orderby=orderby,
                                                       list_id=list_id,
                                                       layout=layout)

            if numrows == 0:
                # Empty table or just no match?

                #table = resource.table
                #if "deleted" in table:
                #    available_records = current.db(table.deleted != True)
                #else:
                #    available_records = current.db(table._id > 0)
                #if available_records.select(table._id,
                #                            limitby=(0, 1)).first():
                #    empty = self.crud_string(resource.tablename,
                #                             "msg_no_match")
                #else:
                #    empty = self.crud_string(resource.tablename,
                #                             "msg_list_empty")

                s3.no_formats = True
                if r.component and "showadd_btn" in output:
                    # Hide the list and show the form by default
                    del output["showadd_btn"]
                    #empty = ""
            #else:
            #    empty = None

            # Allow customization of the datalist Ajax-URL
            # Note: the Ajax-URL must use the .dl representation and
            # plain.html view for pagination to work properly!
            ajax_url = attr.get("list_ajaxurl", None)
            if not ajax_url:
                vars = dict((k,v) for k, v in r.get_vars.iteritems()
                                  if k not in ("start", "limit"))
                ajax_url = r.url(representation="dl", vars=vars)

            # Render the list (even if empty => Ajax-section is required
            # in any case to be able to Ajax-refresh e.g. after adding
            # new records or changing the filter)
            if representation == "dl" or not limit:
                limit = numrows
            dl = datalist.html(start = start if start else 0,
                               limit = limit,
                               pagesize = pagelength,
                               rowsize = rowsize,
                               ajaxurl = ajax_url)
            #if empty:
            #    # Insert empty message
            #    dl.insert(0, DIV(empty, _class="empty"))
            data = dl
        else:
            r.error(415, current.ERROR.BAD_FORMAT)


        if representation == "html":

            # View + data
            response.view = self._view(r, "list_filter.html")
            output["items"] = data

        elif representation == "dl":

            # View + data
            response.view = "plain.html"
            output["item"] = data

        elif representation == "popup":

            # View + data
            response.view = "popup.html"
            output["items"] = data
            # Pagination Support (normally added by views/dataLists.html)
            if s3.debug:
                appname = current.request.application
                sappend = s3.scripts.append
                sappend("/%s/static/scripts/jquery.infinitescroll.js" % appname)
                sappend("/%s/static/scripts/jquery.viewport.js" % appname)
                sappend("/%s/static/scripts/S3/s3.dataLists.js" % appname)
            else:
                s3.scripts.append("/%s/static/scripts/S3/s3.dataLists.min.js" % current.request.application)

        return output

    # -------------------------------------------------------------------------
dataset/ETHPy150Open sahana/eden/modules/s3/s3crud.py/S3CRUD._datalist/original