Code reference › models › person

class

User

pretalx.person.models.user.User source

The pretalx user model, used for all kinds of persons who interact with pretalx: Organisers, reviewers, submitters, speakers, attendees.

Fields 20

idAutoFieldpk
codeCharFieldnulluniquesource
code = models.CharField(max_length=16, unique=True, null=True)
nickCharFieldnullsource
nick = models.CharField(max_length=60, null=True, blank=True)
nameCharFieldsourcePlease enter the name you wish to be displayed publicly. This name will be used for all events you are participating in on this server.
name = models.CharField(
    max_length=120,
    verbose_name=_("Name"),
    help_text=_(
        "Please enter the name you wish to be displayed publicly. This name will be used for all events you are participating in on this server."
    ),
    validators=[validate_username],
)
emailEmailFielduniquesource
email = models.EmailField(
    # We set unique=True to silence Django's warnings, as it does not recognise
    # UniqueConstraint(Lower(...)) as enforcing uniqueness.
    unique=True,
    verbose_name=_("Account email"),
)
email_verification_stateCharFieldsource
email_verification_state = models.CharField(
    max_length=10,
    choices=EmailVerificationState.choices,
    default=EmailVerificationState.UNVERIFIED,
)
pending_emailEmailFieldnullsource
pending_email = models.EmailField(null=True, blank=True)
pending_email_sentDateTimeFieldnullsource
pending_email_sent = models.DateTimeField(null=True, blank=True)
createdDateTimeFieldsource
created = models.DateTimeField(verbose_name=_("Created"), auto_now_add=True)
is_activeBooleanFieldsourceInactive users are not allowed to log in.
is_active = models.BooleanField(
    default=True, help_text="Inactive users are not allowed to log in."
)
is_staffBooleanFieldsourceA default Django flag. Not in use in pretalx.
is_staff = models.BooleanField(
    default=False, help_text="A default Django flag. Not in use in pretalx."
)
is_administratorBooleanFieldsourceShould only be ``True`` for people with administrative access to the server pretalx runs on.
is_administrator = models.BooleanField(
    default=False,
    help_text="Should only be ``True`` for people with administrative access to the server pretalx runs on.",
)
is_superuserBooleanFieldsourceNever set this flag to ``True``, since it short-circuits all authorisation mechanisms.
is_superuser = models.BooleanField(
    default=False,
    help_text="Never set this flag to ``True``, since it short-circuits all authorisation mechanisms.",
)
localeCharFieldsource
locale = models.CharField(
    max_length=32,
    default=settings.LANGUAGE_CODE,
    choices=settings.LANGUAGES,
    verbose_name=_("Preferred language"),
)
timezoneCharFieldsource
timezone = models.CharField(
    choices=[(tz, tz) for tz in TIMEZONE_CHOICES], max_length=32, default="UTC"
)
profile_pictureForeignKeynullProfilePicturesource
profile_picture = models.ForeignKey(
    "person.ProfilePicture",
    null=True,
    blank=True,
    on_delete=models.SET_NULL,
    related_name="users",
)
pw_reset_tokenCharFieldnullsource
pw_reset_token = models.CharField(
    null=True, max_length=160, verbose_name="Password reset token"
)
pw_reset_timeDateTimeFieldnullsource
pw_reset_time = models.DateTimeField(null=True, verbose_name="Password reset time")
passwordCharFieldAbstractBaseUser

on django.contrib.auth.base_user.AbstractBaseUser

password = models.CharField(_("password"), max_length=128)
last_loginDateTimeFieldnullAbstractBaseUser

on django.contrib.auth.base_user.AbstractBaseUser

last_login = models.DateTimeField(_("last login"), blank=True, null=True)
Reverse relations 14
auth_tokenOneToOneRel→ Token
log_entriesManyToOneRelActivityLog
teamsManyToManyRelTeam
attendee_profilesManyToOneRelAttendeeProfile
api_tokensManyToOneRelUserApiToken
picturesManyToOneRelProfilePicture
event_preferencesManyToOneRelUserEventPreferences
profilesManyToOneRelSpeakerProfile
submission_commentsManyToOneRelSubmissionComment
reviewsManyToOneRelReview
assigned_reviewsManyToManyRelSubmission
submission_favouritesManyToOneRelSubmissionFavourite
groupsManyToManyField→ Group
user_permissionsManyToManyField→ Permission

Attributes 3

EMAIL_FIELD'email'
USERNAME_FIELD'email'
objects<django.db.models.manager.UserManagerFromUserQuerySet>
Inherited attributes 8
REQUIRED_FIELDS[]AbstractBaseUser
code_charset['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '3', '7', '8', '9']GenerateCode
code_length6GenerateCode
code_property'code'GenerateCode
code_scope()GenerateCode
is_activeTrueAbstractBaseUser
log_parentNoneLogMixin
log_prefixNoneLogMixin

Properties 5

Defined here

cached_teamssource
@cached_property
def cached_teams(self):
    from pretalx.event.models import Team  # noqa: PLC0415 -- circular import

    teams = list(self.teams.all())
    by_pk = {}
    for team in teams:
        team.limit_event_pks = set()
        team.limit_track_pks = set()
        by_pk[team.pk] = team
    event_rows = Team.limit_events.through.objects.filter(
        team__in=[team for team in teams if not team.all_events]
    ).values_list("team", "event")
    for team_pk, event_pk in event_rows:
        by_pk[team_pk].limit_event_pks.add(event_pk)
    track_rows = Team.limit_tracks.through.objects.filter(
        team__in=[team for team in teams if team.is_reviewer]
    ).values_list("team", "track")
    for team_pk, track_pk in track_rows:
        by_pk[team_pk].limit_track_pks.add(track_pk)
    return teams

From ProfilePictureMixin pretalx.person.models.picture

avatarsource
@cached_property
def avatar(self):
    if self.profile_picture_id:
        return self.profile_picture.avatar
avatar_urlsourceRelative avatar URL, safe for use in HTML templates served from any host (main site or an event's custom domain).

For absolute URLs (API responses, exports, widget data, emails), use get_avatar_url() instead.

@cached_property
def avatar_url(self):
    """Relative avatar URL, safe for use in HTML templates served from any
    host (main site or an event's custom domain).

    For absolute URLs (API responses, exports, widget data, emails), use
    :meth:`get_avatar_url` instead.
    """
    if self.profile_picture_id:
        return self.profile_picture.avatar_url

From AbstractBaseUser django.contrib.auth.base_user

Standard Django API, unchanged — is_anonymous, is_authenticated.
is_anonymousis_authenticated

Methods 68

Defined here

clean()sourceHook for doing any extra model-wide validation after clean() has been called on every field by self.clean_fields.

on pretalx.person.models.user.User source

Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field defined by NON_FIELD_ERRORS.

def clean(self):
    super().clean()
    if self.email:
        self.email = self.email.lower().strip()
    validate_email_unique(
        self.email, exclude_user=None if self._state.adding else self
    )

on django.contrib.auth.base_user.AbstractBaseUser

Hook for doing any extra model-wide validation after clean() has been called on every field by self.clean_fields. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field defined by NON_FIELD_ERRORS.

def clean(self):
    setattr(self, self.USERNAME_FIELD, self.normalize_username(self.get_username()))

on django.db.models.Model

Hook for doing any extra model-wide validation after clean() has been called on every field by self.clean_fields. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field defined by NON_FIELD_ERRORS.

def clean(self):
    """
    Hook for doing any extra model-wide validation after clean() has been
    called on every field by self.clean_fields. Any ValidationError raised
    by this method will not be associated with a particular field; it will
    have a special-case association with the field defined by
    NON_FIELD_ERRORS.
    """
    pass
delete_files()sourceSchedule cleanup of every uploaded file attached to this object.

on pretalx.person.models.user.User source

Public hook: called by delete() and by anonymisation paths (e.g. person.domain.user.deactivate_user) that want to drop files without removing the row. Overridable by subclasses that need to recurse into related objects.

def delete_files(self):
    for picture in self.pictures.all():
        picture.delete()
    return super().delete_files()

on pretalx.common.models.mixins.FileCleanupMixin source

Schedule cleanup of every uploaded file attached to this object.

Public hook: called by delete() and by anonymisation paths (e.g. person.domain.user.deactivate_user) that want to drop files without removing the row. Overridable by subclasses that need to recurse into related objects.

def delete_files(self):
    """Schedule cleanup of every uploaded file attached to this object.

    Public hook: called by ``delete()`` and by anonymisation paths
    (e.g. ``person.domain.user.deactivate_user``) that want to drop
    files without removing the row. Overridable by subclasses that
    need to recurse into related objects."""
    for field in self._file_fields:
        value = getattr(self, field, None)
        if not value:
            continue
        with suppress(Exception):
            self._schedule_file_cleanup(field=field, path=value.path)
get_display_name(allow_empty=False) -> strsourceReturns a user's name or 'Unnamed user' (or, with allow_empty, an empty string).
def get_display_name(self, allow_empty=False) -> str:
    """Returns a user's name or 'Unnamed user' (or, with allow_empty, an empty string)."""
    if allow_empty:
        return self.name or ""
    return str(self)
get_event_preferences(event)source
def get_event_preferences(self, event):
    cache_key = event.pk if event else None
    if preferences := self.event_preferences_cache.get(cache_key):
        return preferences

    preferences, _ = UserEventPreferences.objects.get_or_create(
        event=event, user=self
    )
    self.event_preferences_cache[cache_key] = preferences
    return preferences
get_events_for_permission(**kwargs)sourceReturns a queryset of events for which this user as all of the given permissions.

Permissions are given as named arguments, e.g. get_events_for_permission(is_reviewer=True).

def get_events_for_permission(self, **kwargs):
    """Returns a queryset of events for which this user as all of the given
    permissions.

    Permissions are given as named arguments, e.g.
    ``get_events_for_permission(is_reviewer=True)``.
    """
    if self.is_administrator:
        return Event.objects.all()

    orga_teams = self.teams.filter(**kwargs)
    absolute = orga_teams.filter(all_events=True).values_list(
        "organiser", flat=True
    )
    relative = orga_teams.filter(all_events=False).values_list(
        "limit_events", flat=True
    )
    return Event.objects.filter(
        models.Q(organiser__in=absolute) | models.Q(pk__in=relative)
    ).distinct()
get_events_with_any_permission()source
def get_events_with_any_permission(self):
    if self.is_administrator:
        return Event.objects.all()

    if "teams" in getattr(self, "_prefetched_objects_cache", {}):
        events = {}
        for team in self.teams.all():
            if team.all_events:
                for event in team.organiser.events.all():
                    events[event.pk] = event
            else:
                for event in team.limit_events.all():
                    events[event.pk] = event
        return events.values()

    return Event.objects.filter(
        models.Q(
            organiser_id__in=self.teams.filter(all_events=True).values_list(
                "organiser", flat=True
            )
        )
        | models.Q(id__in=self.teams.values_list("limit_events__id", flat=True))
    )
get_initials() -> strsource
def get_initials(self) -> str:
    return "".join(part[0] for part in self.get_display_name().split()[:2]).upper()
get_locale_for_event(event)source
def get_locale_for_event(self, event):
    if self.locale in event.locales:
        return self.locale
    return event.locale
get_permissions_for_event(event) -> setsourceReturns a set of all permission a user has for the given event.
def get_permissions_for_event(self, event) -> set:
    """Returns a set of all permission a user has for the given event."""
    cached = self.event_permission_cache.get(event.pk)
    if cached and "permissions" in cached:
        return cached["permissions"]
    permissions = set()
    if self.is_administrator:
        permissions = {
            "can_create_events",
            "can_change_teams",
            "can_change_organiser_settings",
            "can_change_event_settings",
            "can_change_submissions",
            # No reviewer permissions; even admins should not be
            # able to review proposals without explicit perms.
        }
    teams = [
        team
        for team in self.cached_teams
        if team.organiser_id == event.organiser_id
        and (team.all_events or event.pk in team.limit_event_pks)
    ]
    reviewer_team_pks = set()
    for team in teams:
        permissions |= team.permission_set
        if not team.is_reviewer or "__all__" in reviewer_team_pks:
            continue
        if not team.limit_track_pks:
            # Blanket reviewer team: bypass any track restrictions.
            # Sentinel is resolved lazily in get_reviewer_tracks.
            reviewer_team_pks = {"__all__"}
        else:
            reviewer_team_pks.add(team.pk)
    self.event_permission_cache[event.pk] = {
        "permissions": permissions,
        "reviewer_team_pks": reviewer_team_pks,
    }
    return permissions
get_reviewer_tracks(event)sourceReturn this user's reviewer track restriction for the event, as a frozenset of pks, or None if all tracks are accessible.
def get_reviewer_tracks(self, event):
    """Return this user's reviewer track restriction for the event,
    as a frozenset of pks, or None if all tracks are accessible."""
    permissions = self.get_permissions_for_event(event)
    if "is_reviewer" not in permissions:
        raise ValueError(f"User {self.pk} is not a reviewer for event {event.pk}")
    cached = self.event_permission_cache[event.pk]
    if "reviewer_tracks" in cached:
        return cached["reviewer_tracks"]
    reviewer_team_pks = cached["reviewer_team_pks"]
    if "__all__" in reviewer_team_pks:
        reviewer_tracks = None
    else:
        reviewer_tracks = frozenset(
            event.tracks.filter(limit_teams__in=reviewer_team_pks).values_list(
                "pk", flat=True
            )
        )
    cached["reviewer_tracks"] = reviewer_tracks
    return reviewer_tracks
get_speaker(event, create=True, origin=SpeakerProfileOrigin.CFP)sourceRetrieve (and/or create) SpeakerProfile for this user.

With create=False, returns None instead of creating a profile when the user has none for the event. origin is only applied when a profile is created.

def get_speaker(self, event, create=True, origin=SpeakerProfileOrigin.CFP):
    """Retrieve (and/or create) SpeakerProfile for this user.

    With create=False, returns None instead of creating a profile when the
    user has none for the event.
    origin is only applied when a profile is created.
    """
    if speaker := self.speaker_cache.get(event.pk):
        return speaker

    if hasattr(self, "_speakers") and len(self._speakers) == 1:
        speaker = self._speakers[0]
        if speaker.event_id == event.pk:
            self.speaker_cache[event.pk] = speaker
            return speaker

    try:
        speaker = self.profiles.select_related("profile_picture").get(event=event)
        speaker.user = self
        speaker.event = event
    except ObjectDoesNotExist:
        if not create:
            return None
        speaker = SpeakerProfile(
            event=event, user=self, name=self.name, origin=origin
        )
        speaker.save()

    self.speaker_cache[event.pk] = speaker
    return speaker
has_perm(perm, obj, *args, **kwargs)sourceReturn True if the user has the specified permission.

on pretalx.person.models.user.User source

Query all available auth backends, but return immediately if any backend returns True. Thus, a user who has permission from a single auth backend is assumed to have permission in general. If an object is provided, check permissions for that object.

def has_perm(self, perm, obj, *args, **kwargs):
    cached_result = None
    if not getattr(obj, "pk", None):
        return super().has_perm(perm, obj, *args, **kwargs)
    with suppress(TypeError):
        cached_result = self.permission_cache.get((perm, obj))
    if cached_result is not None:
        return cached_result
    result = super().has_perm(perm, obj, *args, **kwargs)
    self.permission_cache[(perm, obj)] = result
    return result

on django.contrib.auth.models.PermissionsMixin

Return True if the user has the specified permission. Query all available auth backends, but return immediately if any backend returns True. Thus, a user who has permission from a single auth backend is assumed to have permission in general. If an object is provided, check permissions for that object.

def has_perm(self, perm, obj=None):
    """
    Return True if the user has the specified permission. Query all
    available auth backends, but return immediately if any backend returns
    True. Thus, a user who has permission from a single auth backend is
    assumed to have permission in general. If an object is provided, check
    permissions for that object.
    """
    # Active superusers have all permissions.
    if self.is_active and self.is_superuser:
        return True

    # Otherwise we need to check the backends.
    return _user_has_perm(self, perm, obj)
log_action(action, person=None, content_object=None, **kwargs)source

on pretalx.person.models.user.User source

def log_action(self, action, person=None, content_object=None, **kwargs):
    return super().log_action(
        action=action,
        person=person or self,
        content_object=content_object or self,
        **kwargs,
    )

on pretalx.common.models.mixins.LogMixin source

def log_action(
    self,
    action,
    data=None,
    person=None,
    orga=False,
    content_object=None,
    old_data=None,
    new_data=None,
):
    if self._state.adding or not isinstance(self.pk, int):
        return

    if action.startswith("."):
        if self.log_prefix:
            action = f"{self.log_prefix}{action}"
        else:
            return

    if old_data is not None or new_data is not None:
        from pretalx.common.log import (  # noqa: PLC0415 -- thin method
            compute_log_changes,
        )

        changes = compute_log_changes(old_data, new_data)
        if not changes and not data:
            return
        if changes:
            if data is None:
                data = {}
            data["changes"] = changes

    if data:
        if not isinstance(data, dict):
            raise TypeError(
                f"Logged data should always be a dictionary, not {type(data)}."
            )
        for key in data:
            if any(sensitive_key in key for sensitive_key in SENSITIVE_KEYS):
                data[key] = "********" if data[key] else data[key]
        data = json_roundtrip(data)

    return ActivityLog.objects.create(
        person=person,
        content_object=content_object or self,
        action_type=action,
        data=data,
        is_orga_action=orga,
        **self._log_event_kwargs(),
    )
__init__(*args, **kwargs)sourceInitialize self.

on pretalx.person.models.user.User source

See help(type(self)) for accurate signature.

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.permission_cache = {}
    self.speaker_cache = {}
    self.event_permission_cache = {}
    self.event_preferences_cache = {}

on django.db.models.Model

Initialize self. See help(type(self)) for accurate signature.

def __init__(self, *args, **kwargs):
    # Alias some things as locals to avoid repeat global lookups
    cls = self.__class__
    opts = self._meta
    _setattr = setattr
    _DEFERRED = DEFERRED
    if opts.abstract:
        raise TypeError("Abstract models cannot be instantiated.")

    pre_init.send(sender=cls, args=args, kwargs=kwargs)

    # Set up the storage for instance state
    self._state = ModelState()

    # There is a rather weird disparity here; if kwargs, it's set, then
    # args overrides it. It should be one or the other; don't duplicate the
    # work The reason for the kwargs check is that standard iterator passes
    # in by args, and instantiation for iteration is 33% faster.
    if len(args) > len(opts.concrete_fields):
        # Daft, but matches old exception sans the err msg.
        raise IndexError("Number of args exceeds number of fields")

    if not kwargs:
        fields_iter = iter(opts.concrete_fields)
        # The ordering of the zip calls matter - zip throws StopIteration
        # when an iter throws it. So if the first iter throws it, the
        # second is *not* consumed. We rely on this, so don't change the
        # order without changing the logic.
        for val, field in zip(args, fields_iter):
            if val is _DEFERRED:
                continue
            _setattr(self, field.attname, val)
    else:
        # Slower, kwargs-ready version.
        fields_iter = iter(opts.fields)
        for val, field in zip(args, fields_iter):
            if val is _DEFERRED:
                continue
            _setattr(self, field.attname, val)
            if kwargs.pop(field.name, NOT_PROVIDED) is not NOT_PROVIDED:
                raise TypeError(
                    f"{cls.__qualname__}() got both positional and "
                    f"keyword arguments for field '{field.name}'."
                )

    # Now we're left with the unprocessed fields that *must* come from
    # keywords, or default.

    for field in fields_iter:
        is_related_object = False
        # Virtual field
        if field.column is None or field.generated:
            continue
        if kwargs:
            if isinstance(field.remote_field, ForeignObjectRel):
                try:
                    # Assume object instance was passed in.
                    rel_obj = kwargs.pop(field.name)
                    is_related_object = True
                except KeyError:
                    try:
                        # Object instance wasn't passed in -- must be an
                        # ID.
                        val = kwargs.pop(field.attname)
                    except KeyError:
                        val = field.get_default()
            else:
                try:
                    val = kwargs.pop(field.attname)
                except KeyError:
                    # This is done with an exception rather than the
                    # default argument on pop because we don't want
                    # get_default() to be evaluated, and then not used.
                    # Refs #12057.
                    val = field.get_default()
        else:
            val = field.get_default()

        if is_related_object:
            # If we are passed a related instance, set it using the
            # field.name instead of field.attname (e.g. "user" instead of
            # "user_id") so that the object gets properly cached (and type
            # checked) by the RelatedObjectDescriptor.
            if rel_obj is not _DEFERRED:
                _setattr(self, field.name, rel_obj)
        else:
            if val is not _DEFERRED:
                _setattr(self, field.attname, val)

    if kwargs:
        property_names = opts._property_names
        unexpected = ()
        for prop, value in kwargs.items():
            # Any remaining kwargs must correspond to properties or virtual
            # fields.
            if prop in property_names:
                if value is not _DEFERRED:
                    _setattr(self, prop, value)
            else:
                try:
                    opts.get_field(prop)
                except FieldDoesNotExist:
                    unexpected += (prop,)
                else:
                    if value is not _DEFERRED:
                        _setattr(self, prop, value)
        if unexpected:
            unexpected_names = ", ".join(repr(n) for n in unexpected)
            raise TypeError(
                f"{cls.__name__}() got unexpected keyword arguments: "
                f"{unexpected_names}"
            )
    super().__init__()
    post_init.send(sender=cls, instance=self)
__str__() -> strsourceReturn str(self).

on pretalx.person.models.user.User source

def __str__(self) -> str:
    return self.name or str(_("Unnamed user"))

on django.contrib.auth.base_user.AbstractBaseUser

Return str(self).

def __str__(self):
    return self.get_username()

on django.db.models.Model

Return str(self).

def __str__(self):
    return "%s object (%s)" % (self.__class__.__name__, self.pk)

From ProfilePictureMixin pretalx.person.models.picture

get_avatar_url(event=None, thumbnail=None)sourceAbsolute avatar URL, optionally for a thumbnail size.

When the related event has a custom domain, that domain is used as the base; otherwise settings.SITE_URL is used. event defaults to self.event when the model defines one (e.g. SpeakerProfile).

def get_avatar_url(self, event=None, thumbnail=None):
    """Absolute avatar URL, optionally for a thumbnail size.

    When the related event has a custom domain, that domain is used as
    the base; otherwise ``settings.SITE_URL`` is used. ``event`` defaults
    to ``self.event`` when the model defines one (e.g. ``SpeakerProfile``).
    """
    if not self.profile_picture_id:
        return ""
    if event is None:
        event = getattr(self, "event", None)
    return self.profile_picture.get_avatar_url(event=event, thumbnail=thumbnail)

From PermissionsMixin django.contrib.auth.models

Standard Django API, unchanged — aget_all_permissions(), aget_group_permissions(), aget_user_permissions() and 8 more.
aget_all_permissionsaget_group_permissionsaget_user_permissionsahas_module_permsahas_permahas_permsget_all_permissionsget_group_permissionsget_user_permissionshas_module_permshas_perms

From GenerateCode pretalx.common.models.mixins

assign_code(length=None)source
def assign_code(self, length=None):
    length = length or self.code_length
    while True:
        code = self.generate_code(length=length)
        filter_kwargs = {f"{self.code_property}__iexact": code}
        for field in self.code_scope:
            filter_kwargs[field] = getattr(self, field)
        with scopes_disabled():
            if not self.__class__.objects.filter(**filter_kwargs).exists():
                setattr(self, self.code_property, code)
                return
save(*args, **kwargs)source

on pretalx.common.models.mixins.GenerateCode source

def save(self, *args, **kwargs):
    if getattr(self, self.code_property, None):
        return super().save(*args, **kwargs)

    # Auto-generate code with retry loop to handle unlikely race conditions
    if "update_fields" in kwargs:
        kwargs["update_fields"] = {self.code_property}.union(
            kwargs["update_fields"]
        )
    for attempt in range(
        3
    ):  # pragma: no branch -- loop always exits via return or raise
        self.assign_code()
        try:
            with transaction.atomic():
                return super().save(*args, **kwargs)
        except IntegrityError:
            if attempt == 2:
                raise
            setattr(self, self.code_property, None)

on pretalx.common.models.mixins.FileCleanupMixin source

def save(self, *args, **kwargs):
    update_fields = kwargs.get("update_fields")
    if self._state.adding or (
        update_fields and not set(self._file_fields) & set(update_fields)
    ):
        return super().save(*args, **kwargs)

    try:
        pre_save_instance = self.__class__.objects.get(pk=self.pk)
    except ObjectDoesNotExist:
        return super().save(*args, **kwargs)

    old_files = {}
    for field in self._file_fields:
        if old_value := getattr(pre_save_instance, field):
            new_value = getattr(self, field)
            if new_value and old_value.path != new_value.path:
                old_files[field] = old_value.path

    result = super().save(*args, **kwargs)
    for field, path in old_files.items():
        self._schedule_file_cleanup(field=field, path=path)
    return result

on django.contrib.auth.base_user.AbstractBaseUser

Save the current instance. Override this in a subclass if you want to control the saving process.

The 'force_insert' and 'force_update' parameters can be used to insist that the "save" must be an SQL insert or update (or equivalent for non-SQL backends), respectively. Normally, they should not be set.

def save(self, **kwargs):
    super().save(**kwargs)
    if self._password is not None:
        password_validation.password_changed(self._password, self)
        self._password = None

on django.db.models.Model

Save the current instance. Override this in a subclass if you want to control the saving process.

The 'force_insert' and 'force_update' parameters can be used to insist that the "save" must be an SQL insert or update (or equivalent for non-SQL backends), respectively. Normally, they should not be set.

def save(
    self,
    *,
    force_insert=False,
    force_update=False,
    using=None,
    update_fields=None,
):
    """
    Save the current instance. Override this in a subclass if you want to
    control the saving process.

    The 'force_insert' and 'force_update' parameters can be used to insist
    that the "save" must be an SQL insert or update (or equivalent for
    non-SQL backends), respectively. Normally, they should not be set.
    """

    self._prepare_related_fields_for_save(operation_name="save")

    using = using or router.db_for_write(self.__class__, instance=self)
    if force_insert and (force_update or update_fields):
        raise ValueError("Cannot force both insert and updating in model saving.")

    deferred_non_generated_fields = {
        f.attname
        for f in self._meta.concrete_fields
        if f.attname not in self.__dict__ and f.generated is False
    }
    if update_fields is not None:
        # If update_fields is empty, skip the save. We do also check for
        # no-op saves later on for inheritance cases. This bailout is
        # still needed for skipping signal sending.
        if not update_fields:
            return

        update_fields = frozenset(update_fields)
        field_names = self._meta._non_pk_concrete_field_names
        not_updatable_fields = update_fields.difference(field_names)

        if not_updatable_fields:
            raise ValueError(
                "The following fields do not exist in this model, are m2m "
                "fields, primary keys, or are non-concrete fields: %s"
                % ", ".join(not_updatable_fields)
            )

    # If saving to the same database, and this model is deferred, then
    # automatically do an "update_fields" save on the loaded fields.
    elif (
        not force_insert
        and deferred_non_generated_fields
        and using == self._state.db
        and self._is_pk_set()
    ):
        field_names = set()
        pk_fields = self._meta.pk_fields
        for field in self._meta.concrete_fields:
            if field not in pk_fields and not hasattr(field, "through"):
                field_names.add(field.attname)
        loaded_fields = field_names.difference(deferred_non_generated_fields)
        if loaded_fields:
            update_fields = frozenset(loaded_fields)

    self.save_base(
        using=using,
        force_insert=force_insert,
        force_update=force_update,
        update_fields=update_fields,
    )

From LogMixin pretalx.common.models.mixins

delete(*args, log_kwargs=None, skip_log=False, **kwargs)source

on pretalx.common.models.mixins.LogMixin source

def delete(self, *args, log_kwargs=None, skip_log=False, **kwargs):
    parent = self.log_parent
    result = super().delete(*args, **kwargs)
    if (
        not skip_log
        and parent
        and getattr(parent, "log_action", None)
        and self.log_prefix
    ):
        log_kwargs = log_kwargs or {}
        parent.log_action(f"{self.log_prefix}.delete", **log_kwargs)
    return result

on pretalx.common.models.mixins.FileCleanupMixin source

def delete(self, *args, **kwargs):
    self.delete_files()
    return super().delete(*args, **kwargs)

on django.db.models.Model

def delete(self, using=None, keep_parents=False):
    if not self._is_pk_set():
        raise ValueError(
            "%s object can't be deleted because its %s attribute is set "
            "to None." % (self._meta.object_name, self._meta.pk.attname)
        )
    using = using or router.db_for_write(self.__class__, instance=self)
    collector = Collector(using=using, origin=self)
    collector.collect([self], keep_parents=keep_parents)
    return collector.delete()
get_instance_data()sourceGet a dictionary of field values for this instance.

Used for change tracking in log_action. Excludes auto-updated fields like timestamps and sensitive data. Does not handle many-to-many fields.

def get_instance_data(self):
    """Get a dictionary of field values for this instance.

    Used for change tracking in log_action. Excludes auto-updated
    fields like timestamps and sensitive data.
    Does not handle many-to-many fields.
    """
    excluded_fields = {
        "created",
        "updated",
        "is_active",
        "last_login",
        "user",
        "event",
        "code",
    }
    data = {}

    for field in self._meta.fields:
        if (
            field.name in excluded_fields
            or field.name in SENSITIVE_KEYS
            or "thumbnail" in field.name
            or getattr(field, "auto_now", False)
            or getattr(field, "auto_now_add", False)
        ):
            continue

        if isinstance(field, models.ForeignKey):
            data[field.name] = getattr(self, field.attname, None)
            continue

        value = getattr(self, field.name, None)

        if isinstance(field, models.FileField):
            data[field.name] = value.name if value else None
        elif isinstance(field, models.UUIDField):
            data[field.name] = str(value) if value else None
        elif isinstance(value, LazyI18nString):
            if isinstance(getattr(value, "data", None), dict):
                data[field.name] = {k: v for k, v in value.data.items() if v}
            else:
                data[field.name] = str(value)
        else:
            data[field.name] = json_roundtrip(value)
    return data
logged_actions()source
def logged_actions(self):
    return (
        ActivityLog.objects.filter(
            content_type=ContentType.objects.get_for_model(type(self)),
            object_id=self.pk,
        )
        .select_related("event", "person")
        .prefetch_related("content_object")
    )

From FileCleanupMixin pretalx.common.models.mixins

process_image(field, generate_thumbnail=False)source
def process_image(self, field, generate_thumbnail=False):
    task_process_image.apply_async(
        kwargs={
            "field": field,
            "model": self._meta.model_name.capitalize(),
            "pk": self.pk,
            "generate_thumbnail": generate_thumbnail,
        },
        countdown=10,
    )

From AbstractBaseUser django.contrib.auth.base_user

Standard Django API, unchanged — acheck_password(), check_password(), get_session_auth_fallback_hash() and 6 more.
acheck_passwordcheck_passwordget_session_auth_fallback_hashget_session_auth_hashget_usernamehas_usable_passwordnatural_keyset_passwordset_unusable_password

From Model django.db.models

Standard Django API, unchanged — full_clean(), adelete(), arefresh_from_db() and 18 more.
adeletearefresh_from_dbasaveclean_fieldsdate_error_messagefull_cleanget_constraintsget_deferred_fieldsprepare_database_saverefresh_from_dbsave_baseserializable_valueunique_error_messagevalidate_constraintsvalidate_unique__eq____getstate____hash____reduce____repr____setstate__

Added at runtime

Added by Django or another library dynamically after class creation.
get_email_verification_state_displayget_locale_displayget_next_by_createdget_previous_by_createdget_timezone_display