Как работать с signals (post_save)?

Я имею схему пользователей списками (medical, patient, physiotherapist), что происходит от класса AbstractUser, чтобы это использовать в request, как видят в следующих моделях:

#models.py

from __future__ import unicode_literals
from django.conf import settings
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.contrib.auth import get_user_model
from django.dispatch import receiver
from django.db.models.signals import post_save

class User(AbstractUser):
    is_medical = models.BooleanField(default=False)
    is_physiotherapist = models.BooleanField(default=False)
    is_patient = models.BooleanField(default=False)
    slug = models.SlugField(max_length=100, blank=True)
    photo = models.ImageField(upload_to='avatars', null = True, blank = True)

    def get_medical_profile(self):
        medical_profile = None
        if hasattr(self, 'medicalprofile'):
            medical_profile=self.medicalprofile
        return medical_profile

    def get_patient_profile(self):
        patient_profile = None
        if hasattr(self, 'patientprofile'):
            patient_profile = self.patientprofile
        return patient_profile

    def get_physiotherapist_profile(self):
        physiotherapist_profile = None
        if hasattr(self, 'physiotherapistprofile'):
            physiotherapist_profile = self.physiotherapistprofile
        return physiotherapist_profile

    class Meta:
        db_table = 'auth_user'

class MedicalProfile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    name = models.CharField(max_length=64)

class PatientProfile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    name = models.CharField(max_length=64)

class PhysiotherapistProfile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    name = models.CharField(max_length=64)

Что желание состоит в том, что, когда он верит, новый пользователь, автоматического способа, верит себе в Ваш профиль в зависимости от Вашего поля, если медицинский, терпеливый, или физиотерапевт (is_medical, is_patient, is_physiotherapist)

Для этого я использую signal post_save() следующего способа в том же файле models.py, где - мои модели:

В signal я нахожусь enviándo еще три параметра ** kwargs:

  • sender, что является моей моделью пользователей
  • created, параметр booleano, что показывает мне, что инстанция моей модели пользователя AUTH_USER_MODELона была создана
  • instance, инстанция пользователя, который создан

Чтобы знать, что пользователь очень скоро будет создан, каким-то образом я должен расследовать, если в этом request, который я делаю (создавать пользователь), идет этот пользователь или эта инстанция, которая готова быть созданным, для чего я делаю user = self.request.user

    @receiver(post_save, sender=settings.AUTH_USER_MODEL)
    def create_profile_for_new_user(sender, created, instance, **kwargs):
        # Pregunto si en el request va el user, aqui va mi inquietud
        user = self.request.user
        #user = get_user_model()
        if created:
            if user.is_medical:
                profile=MedicalProfile(user=instance)
                profile.save()

Это хорошая логика, но оказывается, что я не определил self и получаю (очевидным способом) эту ошибку

introducir la descripción de la imagen aquí

В методе в create_profile_for_new_user(...) к которому я применяю signal post_save() только у меня есть четыре признака, из-за которого, если я добавляю self как признак в начало

@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_profile_for_new_user(self,sender, created, instance, **kwargs):

он получил бы эту ошибку:

TypeError: create_profile_for_new_user() missing 1 required positional argument: 'self'
127.0.0.1 - - [28/Dec/2015 22:57:04] "GET /admin/userprofile/user/add/?__debugger__=yes&cmd=resource&f=style.css HTTP/1.1" 200 -

Другой выбор, который он созерцал, состоит в том, чтобы получать пользователь, который создан функцией get_user_model()поскольку я это делаю здесь (импортируя заблаговременно функцию просвет эта from django.contrib.auth import get_user_model):

@receiver(post_save, sender=settings.AUTH_USER_MODEL)
    def create_profile_for_new_user(sender, created, instance, **kwargs):
        # Pregunto si en el request va el user, aqui va mi inquietud
        #user = self.request.user
        user = get_user_model()
        if created:
            if user.is_medical:
                profile=MedicalProfile(user=instance)
                profile.save()

Но когда я это делаю, я получаю это сообщение, и он логичен, так как мой объект User (я получая инстанцию модели первоначальный Усер Джанго) не имеет признака тем, что я спрашиваю, в этом случае is_medical

introducir la descripción de la imagen aquí

Согласно предыдущему, не, как то, чтобы спрашивать или расследовать из-за пользователя, чтобы рассматривать Ваши признаки booleanos (is_patient, is_medical, is_physiotherapist) и создавать Ваш соответствующий профиль согласно этому.

Шаг я использую и я появляется другая тревога: Возможно использовать signal post_save для более чем одного намерения?

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

3
задан 29.12.2015, 14:37
3 ответа

Помни, что create_profile_for_new_user это функция, связанная с моделью, это не вид, следовательно ты не имеешь доступа в request. Также это не класс, а следовательно ты не имеешь доступа в self поскольку ты хотел.

Параметр created оно не будет функционировать, как ты хотел, так как ты это используешь в неправильном положении параметра, первый параметр функций, которые получают сигнал, модель, которая посылает сигнал (sender) и второй параметр - инстанция этой модели (instance).

Параметр instance дело в том, что содержит пользователь, который был создан из-за, что следующее действительное:

@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_profile_for_new_user(sender, instance, **kwargs):
    user = instance # 
    # ...

Даже это необходимо, ты мог бы делать это без необходимости распределять переменную user:

@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_profile_for_new_user(sender, instance, **kwargs):
    if instance.is_medical:
        # ...
    elif instance.is_physiotherapist:
        # ...
    elif instance.is_patient
        # ...

Если ты нуждаешься в том, чтобы распределить остальные поля твоей модели, также ты можешь делать это, хотя я подумал, что это уже мы это решили:

@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_profile_for_new_user(sender, instance, **kwargs):
    slug = slugify(instance.first_name)
    User.objects.filter(pk=instance.pk).update(slug=slug)
    # ...

Замечание:

Наблюдай, что ни в одном из примеров я использую параметр created который ты определил inialmente как параметр.

Хотя возможно использовать paŕametro created post_save, имей в виду, что это третий параметр, не второй:

@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_profile_for_new_user(sender, instance, created, **kwargs):
    if created:
        # ...

Обновление:

Проблема, которая у тебя есть на IntegrityError о котором ты упоминаешь в твоих комментариях, проистекает того, что, когда ты logueas, система старается сохранять твою последнюю дату logueo и старались делать это он называется снова в post_save и в конце концов в твою функцию create_profile_for_new_user.

Решение состоит в том, чтобы ты использовал всегда параметр created:

@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_profile_for_new_user(sender, instance, created, **kwargs):
    if created:
        # ...

Если ты это не используешь, функция будет стараться сохранять снова профиль и произведет один IntegrityError так как профиль был создан ранее, когда пользователь был создан изначально.

3
ответ дан 24.11.2019, 15:02
  • 1
    Прекращаться, если. У тебя есть raz и # 243; n. Хотя, если я использую параметр " created" slug post_save не записывает мне профиль пользователя. – bgarcial 29.12.2015, 17:24
  • 2
    Другой одинокой стороны, чем относительно, когда я буду инициализироваться sesi и # 243; n с созданным пользователем, который автоматически создал Ваш профиль medicaluser с signal, он перемещает меня следующее: cldup.com/DPXcPqDQHY.png – bgarcial 29.12.2015, 17:29
  • 3
    @bgarcial то, что говорит тебе ошибку, не что вид быть и # 225; deprecada, что быть, и # 225; deprecado - форма, в которой ты перемещаешь пару и # 225; метр вида, как кажется, в версии 1.10 из Джанго уже не podr и # 225; s перемещать вид как string: 'django.contrib.auth.views.login' – César 29.12.2015, 18:01
  • 4
    @bgarcial смотри мое обновление, решение состоит в том, чтобы использовать всегда параметр created. Ты комментируешь мне – César 29.12.2015, 18:10
  • 5
    @bgarcial пользователь новый? Попробуй debuggear код используя pdb, единственную обязанность и # 237; чтобы создавать профиль, когда пользователь создан, для следующих случаев уже не быть должным и # 237; не создавать чтобы ничего – César 29.12.2015, 20:45

В файле settings.py он должен определять класс, который он получает в наследство от AbstractUser в свойстве AUTH_USER_MODEL а следовательно он остался бы

AUTH_USER_MODEL = "app.User"

С этим он возьмет инстанцию твоего класса, не класса User из-за default (auth. User)

2
ответ дан 24.11.2019, 15:02
  • 1
    Привет Кристиан, если я действительно использую персонализированную модель пользователей и в моем settings уже я считаю это определенным, - из-за этого, из-за чего в signal пара и # 225; метр sender схвати эту и # 237;: sender=settings. AUTH_USER_MODEL. Но то, что я действительно должен смотреть, состоит, как медицинский тип или пользователь получают профиль пользователя, которого я создаю, чтобы спрашивать, если идут в True признак или признаки, если - пользователь терпеливый тип, или пользователь тип физиотерапевт и так в том, чтобы создавать Ваш соответствующий профиль с Вашими специфическими полями, что все это это сделало signal.:) – bgarcial 29.12.2015, 05:25
  • 2

В конце концов, optГ©, из-за того, что работает sobreescribiendo mГ©todo save() из класса AbstractUser вместо того, чтобы работать применяя signal post_save() в нее funciГіn create_profile_for_new_user, так что мои модели User MedicalProfile, PatientProfile и PhisiotherapystProfile остались asГ-:

from __future__ import unicode_literals
from django.conf import settings
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.template.defaultfilters import slugify
from django.dispatch import receiver
from django.db.models.signals import post_save

class User(AbstractUser):
    is_medical = models.BooleanField(default=False)
    is_physiotherapist = models.BooleanField(default=False)
    is_patient = models.BooleanField(default=False)
    slug = models.SlugField(max_length=100, blank=True)
    photo = models.ImageField(upload_to='avatars', null = True, blank = True)

    def save(self, *args, **kwargs):
        user = super(User, self).save( *args, **kwargs)

        # Creating and user with medical, patient and physiotherapist profiles
        if self.is_medical and not MedicalProfile.objects.filter(user=self).exists()\
                and self.is_patient and not PatientProfile.objects.filter(user=self).exists()\
                and self.is_physiotherapist and not PhysiotherapistProfile.objects.filter(user=self).exists():

            medical_profile=MedicalProfile(user=self).save()
            patient_profile=PatientProfile(user=self).save()
            physiotherapist_profile=PhysiotherapistProfile(user=self).save()
            #profile.save()

        # Creating and user with medical and patient profiles
        elif self.is_medical and not MedicalProfile.objects.filter(user=self).exists()\
            and self.is_patient and not PatientProfile.objects.filter(user=self).exists():

            medical_profile=MedicalProfile(user=self).save()
            patient_profile=PatientProfile(user=self).save()

        # Creating and user with medical and physiotherapist profiles
        elif self.is_medical and not MedicalProfile.objects.filter(user=self).exists()\
            and self.is_physiotherapist and not PhysiotherapistProfile.objects.filter(user=self).exists():

            medical_profile=MedicalProfile(user=self).save()
            physiotherapist_profile=PhysiotherapistProfile(user=self).save()

        # Creating and user with physiotherapist and patient profiles
        elif self.is_physiotherapist and not PhysiotherapistProfile.objects.filter(user=self).exists()\
            and self.is_patient and not PatientProfile.objects.filter(user=self).exists():

            physiotherapist_profile = PhysiotherapistProfile(user=self).save()
            patient_profile = PatientProfile(user=self).save()

        # Creating and user with medical profile
        elif self.is_medical and not MedicalProfile.objects.filter(user=self).exists():
            profile = MedicalProfile(user=self)
            profile.save()

        # Creating and user with patient profile
        elif self.is_patient and not PatientProfile.objects.filter(user=self).exists():
            profile = PatientProfile(user=self)
            profile.save()

        # Creating and user with physiotherapist profiles
        elif self.is_physiotherapist and not PhysiotherapistProfile.objects.filter(user=self).exists():
            profile = PhysiotherapistProfile(user=self)
            profile.save()



    # We get the profiles user according with their type
    def get_medical_profile(self):
        medical_profile = None
        if hasattr(self, 'medicalprofile'):
            medical_profile=self.medicalprofile
        return medical_profile

    def get_patient_profile(self):
        patient_profile = None
        if hasattr(self, 'patientprofile'):
            patient_profile = self.patientprofile
        return patient_profile

    def get_physiotherapist_profile(self):
        physiotherapist_profile = None
        if hasattr(self, 'physiotherapistprofile'):
            physiotherapist_profile = self.physiotherapistprofile
        return physiotherapist_profile

    # We redefine the attributes (create db_table attribute) in class Meta to say to Django
    # that users will save in the same table that the Django default user model
    # https://github.com/django/django/blob/master/django/contrib/auth/models.py#L343
    class Meta:

        db_table = 'auth_user'

class MedicalProfile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    #active = models.BooleanField(default=True)
    name = models.CharField(max_length=64)


class PatientProfile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    #active = models.BooleanField(default=True)
    name = models.CharField(max_length=64)


class PhysiotherapistProfile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    #active = models.BooleanField(default=True)
    name = models.CharField(max_length=64)

# Enter the username as slug field
@receiver(post_save, sender = settings.AUTH_USER_MODEL)
def post_save_user(sender, instance, **kwargs):
    slug = slugify(instance.username)
    User.objects.filter(pk=instance.pk).update(slug=slug)

Таким образом, возможно создавать пользователя, который считал все комбинации списков (лечил, пациент, физиотерапевт) возможными.

В любом случае продолжает использовать signal post_save(), примененные в ней funciГіn post_save_user(), чтобы вводить стоимость slug в компьютер в мое поле slug в модели User. Эта стоимость основана на признаке username

Большое спасибо из-за Ваших постоянных ориентаций.:)

2
ответ дан 24.11.2019, 15:02
  • 1
    Обычно он состоит desaconcejable в том, чтобы издавать очень или изменять пользователь Джанго, всегда они рекомендуют делать профиль в и # 241; adido со ссылкой Один в Один, чтобы предотвращать проблемы, изменив модель Усер. Очень хороший ответ, не забывай пометить получающий ответ. – SalahAdDin 13.03.2016, 23:15