'Validator for foreign keys.
@param dbset: a Set of records like db(query), or db itself
@param field: the field in the referenced table
@param label: lookup method for the label corresponding a value,
alternatively a string template to be filled with
values from the record
@param filterby: a field in the referenced table to filter by
@param filter_opts: values for the filterby field which indicate
records to include
@param not_filterby: a field in the referenced table to filter by
@param not_filter_opts: values for not_filterby field which indicate
records to exclude
@param realms: only include records belonging to the listed realms
(if None, all readable records will be included)
@param updateable: only include records in the referenced table which
can be updated by the user (if False, all readable
records will be included)
@param instance_types: if the referenced table is a super-entity, then
only include these instance types (this parameter
is required for super entity lookups!)
@param error_message: the error message to return for failed validation
@param orderby: orderby for the options
@param groupby: groupby for the options
@param left: additional left joins required for the options lookup
(super-entity instance left joins will be included
automatically)
@param multiple: allow multiple values (for list:reference types)
@param zero: add this as label for the None-option (allow selection of "None")
@param sort: sort options alphabetically by their label
@param _and: internal use'

def __init__(self, dbset, field, label=None, filterby=None, filter_opts=None, not_filterby=None, not_filter_opts=None, realms=None, updateable=False, instance_types=None, error_message='invalid    value!', orderby=None, groupby=None, left=None, multiple=False, zero='', sort=True, _and=None):

    if hasattr(dbset, 'define_table'):
        self.dbset = dbset()
    else:
        self.dbset = dbset
    (ktable, kfield) = str(field).split('.')
    if (not label):
        label = ('%%(%s)s' % kfield)
    if isinstance(label, str):
        if regex1.match(str(label)):
            label = ('%%(%s)s' % str(label).split('.')[(-1)])
        ks = regex2.findall(label)
        if (not (kfield in ks)):
            ks += [kfield]
        fields = [('%s.%s' % (ktable, k)) for k in ks]
    elif hasattr(label, 'bulk'):
        ks = [kfield]
        if label.custom_lookup:
            fields = [kfield]
            orderby = field
        else:
            label._setup()
            fields = list(label.fields)
            if (kfield not in fields):
                fields.insert(0, kfield)
    else:
        ks = [kfield]
        try:
            table = current.s3db[ktable]
            fields = [str(f) for f in table if (f.name not in ('wkt', 'the_geom'))]
        except RuntimeError:
            fields = 'all'
    self.fields = fields
    self.label = label
    self.ktable = ktable
    if ((not kfield) or (not len(kfield))):
        self.kfield = 'id'
    else:
        self.kfield = kfield
    self.ks = ks
    self.error_message = error_message
    self.theset = None
    self.orderby = orderby
    self.groupby = groupby
    self.left = left
    self.multiple = multiple
    self.zero = zero
    self.sort = sort
    self._and = _and
    self.filterby = filterby
    self.filter_opts = filter_opts
    self.not_filterby = not_filterby
    self.not_filter_opts = not_filter_opts
    self.realms = realms
    self.updateable = updateable
    self.instance_types = instance_types
