Django-invitations, Django-Allauth: pass model field data from custom invitation to (custom) user object

Viewed 886

I'm combining django-invitations with django-allauth for user invitation and signup.

I'd like the Administrator (when creating an invitation through the Django Admin) to provide extra data (here a foreign key to Patient object). This is archieved by adding an extra field to the (custom) invitation model:

class PatientInvitation (AbstractBaseInvitation):                                                                                                                                                                    
    email = models.EmailField(unique=True, verbose_name=_('e-mail address'),                                                                                                                                         
                              max_length=app_settings.EMAIL_MAX_LENGTH)                                                                                                                                              
    created = models.DateTimeField(verbose_name=_('created'),                                                                                                                                                        
                                   default=timezone.now)                                                                                                                                                                                                                                                                                                                       
    patient = models.ForeignKey(Patient, blank=True, null=True, on_delete=models.CASCADE)                                                                                                                            

    @classmethod                                                                                                                                                                                                     
    def create(cls, email, inviter=None, patient=None,  **kwargs):                                                                                                                                                   
        key = get_random_string(64).lower()                                                                                                                                                                          
        instance = cls._default_manager.create(                                                                                                                                                                      
            email=email,                                                                                                                                                                                             
            key=key,                                                                                                                                                                                                 
            inviter=inviter,                                                                                                                                                                                         
            patient=patient,                                                                                                                                                                                         
            **kwargs)                                                                                                                                                                                                
        return instance                                                                                                                                                                                              

    def key_expired(self):                                                                                                                                                                                           
        expiration_date = (                                                                                                                                                                                          
            self.sent + datetime.timedelta(                                                                                                                                                                          
                days=app_settings.INVITATION_EXPIRY))                                                                                                                                                                
        return expiration_date <= timezone.now()                                                                                                                                                                     

    def send_invitation(self, request, **kwargs):                                                                                                                                                                    
        current_site = kwargs.pop('site', Site.objects.get_current())                                                                                                                                                
        invite_url = reverse('invitations:accept-invite',                                                                                                                                                            
                             args=[self.key])                                                                                                                                                                        
        invite_url = request.build_absolute_uri(invite_url)                                                                                                                                                          
        ctx = kwargs                                                                                                                                                                                                 
        ctx.update({                                                                                                                                                                                                 
            'invite_url': invite_url,                                                                                                                                                                                
            'site_name': current_site.name,                                                                                                                                                                          
            'email': self.email,                                                                                                                                                                                     
            'key': self.key,                                                                                                                                                                                         
            'inviter': self.inviter,                                                                                                                                                                                 
        })                                                                     

When the invited user signs up, I would like this data to end up in the Custom user model:

class customUser(AbstractUser):                                                                                                                                                                                      
    username_validator = MyValidator()                                                                                                                                                                               
    is_patient = models.BooleanField(default=False)                                                                                                                                                                  
    patient = models.ForeignKey(Patient, null=True, blank=True, on_delete=models.CASCADE)                                                                                                                              
    username = models.CharField(                                                                                                                                                                                     
        _('username'),                                                                                                                                                                                               
        max_length=150,                                                                                                                                                                                              
        unique=True,                                                                                                                                                                                                                                                                                                                                                                                                         
    )       

I've looked into the signals to pass the data, but couldn't find how exactly to do this. Another option seems to add the PK of the foreign key to a hidden field on the signup form (this seems unsafe though).

I'm a bit stuck on this one, so if anyone could point me in the right direction, It would be greatly appreciated :)

Regards, Joris

1 Answers

Use allauth's signals instead; you'll have much more options and you can still accomplish exactly what you want.

  1. I would create signals.py in your app directory.

  2. Register your signals file under your apps.py like so:

from django.apps import AppConfig

class AccountsConfig(AppConfig):
    name = 'app_name'

    def ready(self): ###<-----------
        import app_name.signals ###<-----------
  1. Use the user_signed_up signal to update the user with the invitation's data:

signals.py

from allauth.account.signals import user_signed_up
from invitations.utils import get_invitation_model

def user_signed_up(request, user, **kwargs):
    try:
        Invitation = get_invitation_model() ### Get the Invitation model
        invite = Invitation.objects.get(email=user.email) ### Grab the Invitation instance
        user.patient = invite.patient ### Pass your invitation's patient to the related user
        user.save()
    except Invitation.DoesNotExist:
        print("this was probably not an invited user.")


Related