Private data¶
Search endpoints are public by default, so restrict any lookup over private data. If every form
with a LookupWidget is behind a login, require one for all lookups:
IZAYA_LOGIN_REQUIRED = True
Anonymous searches then get a 403, so a session that expires while a form is open shows
login_required_text in the results. This reads request.user, which needs
AuthenticationMiddleware. The system check izaya.W001 reports if it’s missing from MIDDLEWARE.
To keep one lookup public, for example on a public page, override has_access:
class GenreLookup(ModelLookup):
model = Genre
search_fields = ["name__icontains"]
def has_access(self, request):
return True
A has_access override replaces the setting, so call super().has_access(request) to add a rule
on top of it.
Django’s LoginRequiredMiddleware takes over for anonymous users: it redirects their searches to
the login page before izaya sees them. The setting, has_access and login_required_text then
have no effect on those searches, so a lookup can’t opt out to stay public.
Only a False from has_access shows a message. A PermissionDenied raised by a lookup still gets
the project’s 403 page, which the widget ignores, so the results stay closed.
The setting only controls who can search, not what they find. A per-user get_queryset only limits
what can be searched. Limit the form field’s queryset to the same records, usually in the form’s
__init__, as well:
class ListForm(forms.ModelForm):
def __init__(self, *args, user, **kwargs):
super().__init__(*args, **kwargs)
self.fields["previous"].queryset = ReadingList.objects.manageable_by(user)
The field rejects submitted values outside that queryset, and the widget won’t render their labels. A stored value outside it isn’t shown either, so saving the form without that value clears it.
On a field with choices, such as a ChoiceField or a model field with choices, the widget
likewise renders only labels for keys among those choices. A field with neither a queryset nor
choices, such as a CharField, gives the widget nothing to check against. A bound form then
renders the label get_selected returns for any submitted key, so anyone can read the labels of
records they can’t search by submitting their keys. get_selected has no request to limit by, so
use a model or choice field for private data rather than a CharField.