Как отправить проверку электронной почты из админки при обновлении электронной почты

Я присоединился к проекту, где код написан на django 2+. Это система для пациентов и врачей. Когда врач регистрирует пациента, тот получает подтверждение по электронной почте со ссылкой. Как только он нажимает на нее, она может использовать платформу.

На пользовательском интерфейсе в настройках пациентка может обновить свой email, и она получит новую ссылку на свой новый email для подтверждения того, что это ее email. До того, как она нажмет на ссылку подтверждения, атрибут email не изменяется. обновляется только кандидат email и на него отправляется письмо. (если я изменю атрибут email на email_кандидата, то если она ошибется в email_кандидата, она больше не сможет войти в систему)

После клика электронная почта пациента станет электронной почтой кандидата.

Все это работает

В интерфейсе администратора поддержки пациентов агент может помочь пациентам обновить их электронную почту. Но когда запрашивается действие отправки подтверждения электронной почты, кандидат на электронную почту не выбирается. Выбирается только электронная почта пользователя, на которую отправляется подтверждение электронной почты.

Я действительно не понимаю, как вызвать, возможно, ту же функцию обновления электронной почты.

models.py User

class User(AbstractUser):
    objects = UserManager()
    
    is_physician = models.BooleanField(default=False)
    is_patient = models.BooleanField(default=False)
    
    title = models.CharField(choices=TITLE_CHOICES,
                             max_length=10,
                             blank=True,
                             null=True)
    first_name = models.CharField(max_length=254, blank=True, null=True, )
    last_name = models.CharField(max_length=254, blank=True, null=True, )
    birthdate = models.DateField(null=True, blank=True)
    home_phone = PhoneNumberField(blank=True, null=True)
    mobile_phone = PhoneNumberField(blank=True, null=True)
    gender = models.CharField(max_length=1,
                              choices=GENDER_CHOICES,
                              blank=True,
                              null=True)
    
    language = models.CharField(max_length=4,
                                choices=settings.LANGUAGES,
                                default='en',
                                blank=True,
                                null=True)
    
    email = models.EmailField(unique=True, db_index=True,
                              error_messages={
                                  'unique': "Email already exists."
                              }
                              )
    email_candidate = models.EmailField(
        max_length=254,
        blank=True,
        null=True,
        default=None)
    
    username = models.CharField(
        max_length=30,
        unique=True,
        blank=True,
        null=True,
        validators=[
            validators.RegexValidator(
                r'^\w+$',
                'Enter a valid username. This value may contain only '
                'letters, numbers and _ character.',
                'invalid'
            ),
        ],
        error_messages={
            'unique': "Username already exists."
        }
    )
    
    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []
    ordering = ('created',)
    class Meta(object):
        verbose_name = 'User'
        verbose_name_plural = 'Users'
        # abstract = False
        permissions = u_perm.user_permissions
    @property
    def name(self):
        return '{} {}'.format(self.last_name, self.first_name, )

models.py У пациента есть поле OneToOne user

class Patient(models.Model):
    user = models.OneToOneField(
        settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    physician = models.ForeignKey(Physician,
                                  related_name='patients',
                                  null=True,
                                  blank=True,
                                  on_delete=models.SET_NULL)
    address = models.TextField(blank=True, null=True)
    city = models.CharField(max_length=85, null=True, blank=True)
    country = CountryField(null=True, blank=True)
    postal_code = models.CharField(max_length=32, null=True, blank=True)
    reminder_hour_default = models.TimeField(
        'Send Reminder Time',
        default=settings.REMINDER_HOUR_DEFAULT)
    is_eligible = models.BooleanField(default=True)
    def __str__(self):
        return self.user.email
   @receiver(post_save, sender=Patient)
   @receiver(post_save, sender=User)
   def update_status(sender, **kwargs):
    def update_patient(instance):
        # from pending/disabled to active
        current_status = instance.user.status
            instance.save()
            instance.user.save()
            return
    def update_user(instance):
        pass

    instance = kwargs.get('instance')
    method_name = get_inner_method(sender)
    if instance and method_name:
        method_name(instance)

models.py Patient Support

class PatientSupport(Patient):
    class Meta:
        proxy = True
        # Add verbose name
        verbose_name = 'Patient Support'
        verbose_name_plural = 'Patients Support'

serializers.py UserSerializer с рабочей конечной точкой из пользовательского интерфейса пациента под названием update_candidate_email

admin.py PatientSupportAdmin оттуда мне нужно обновить email, отправив подтверждение электронной почты на email_candidate

class PatientSupportAdmin(admin.ModelAdmin):
    list_display = ['pk', 'patient', 'patient_email', 'email_candidate' ]

    list_display_links = ('pk', 'patient')

   
    def get_queryset(self, request):
        qs = super(PatientSupportAdmin, self).get_queryset(request)
        return qs.filter(support_consent=True)

    fieldsets = (
        ('User', {
            'fields': (
                'patient',
                'get_gender',
                'birthdate',
                'home_phone', 'mobile_phone', 'language',
                'email', 'username',
                'date_modified',
                'date_joined',
                'status',
                'user',
            )}),

        ('Patient', {'fields': ('physician',
                                'country',
                                'id_number',
                                )}),

    def patient(self, obj):
        return obj.user.get_full_name()

    def patient_email(self, obj):
        return obj.user.email

    def email_candidate(self, obj):
        return obj.user.email_candidate

    def birthdate(self, obj):
        return obj.user.birthdate or ''

    def home_phone(self, obj):
        return obj.user.home_phone

    def mobile_phone(self, obj):
        return obj.user.mobile_phone

    def email(self, obj):
        return obj.user.email

    def username(self, obj):
        return obj.user.username or ''

    actions = [resend_email_verification,
               ]

admin.py resend_email_verification(), тот, который я мог бы использовать, но он берет только email все еще зарегистрированный как email пользователя, а не email кандидата, чтобы отправить ему подтверждение. это подтверждение по электронной почте

def resend_email_verifcation(modeladmin, request, queryset):
    for user in queryset:
        if 'users/patient' in request.path:
           
            user = user.user
          
        if user.is_patient and not user.patient.is_eligible:
            continue
        site_domain = Site.objects.filter(name__icontains='admin').first()
        token = ResetPasswordToken.objects.create(
            user=user, )
        reset_password_token_created.send(
            sender=modeladmin.__class__, reset_password_token=token)

Итак, важной частью для отправки электронной почты в UserSerializer является

if email_candidate and email_candidate != instance.email_candidate:

Вы можете немного схитрить, чтобы повторно использовать этот метод с новым действием в admin

def send_verification_email_for_email_candidate(modeladmin, request, queryset):
    for user in queryset:
        email_candidate = user.email_candidate
        if not email_candidate:
            continue  # defensive a little bit to ignore other use cases in UserSerializer
        user.email_candidate = f'{email_candidate}random'  # to trigger the condition above
        UserSerializer().update_candidate_email(user, {}, email_candidate)

Но я рекомендую переписать функцию или скопировать эту логическую часть сюда

Вернуться на верх