Создавать объект, только если другой объект успешно создан - PullRequest
1 голос
/ 01 ноября 2019

Я довольно новичок в Django и не знаком с лучшими практиками для этой ситуации (в любом фреймворке / языке, не только в python / django).

Ситуация такова, что когда пользователь впервые регистрируется на моем сайте, я хочу создать для него «организацию», если она не существует, а затем впоследствии создать для него пользователя, который ссылается на организацию. Я никогда не хочу вставлять одно без другого, но мне нужно сначала создать организацию, чтобы можно было сохранить UUID организации для каждого пользователя. В настоящий момент организации все равно будут созданы, даже если возникнут проблемы с созданием пользователя. Это, очевидно, проблема, потому что тогда у меня есть организация без пользователей.

Я не знаю точно, как проверить, что пользователь будет правильно создан перед созданием организации, но мне кажется, что мне нужно что-то в этом роде. Использование commit = false при создании объекта организации не сработает, потому что мне нужно получить UUID. Поэтому я не уверен, что лучший способ продолжить.

Я перезаписываю метод сохранения в сериализаторе популярного пакета аутентификации django-allauth

models.py

class Organization(models.Model):
  alphanumeric_plus_underscore = RegexValidator(r'^[\w]+$', 'Only alphanumeric characters are allowed.')
  id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)  # pylint: disable=invalid-name
  name = models.CharField(max_length=20, unique=True, validators=[alphanumeric_plus_underscore, MinLengthValidator(4)])
  logo = models.FileField(upload_to='files/organization_logos/', null=True, blank=True)

class User(AbstractBaseUser):
  id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)  # pylint: disable=invalid-name
  first_name = models.CharField(_('First Name'), max_length=50)
  last_name = models.CharField(_('Last Name'), max_length=50)
  email = models.EmailField(_('Email address'), unique=True)
  organization = models.ForeignKey(Organization, blank=False, null=False, on_delete=models.DO_NOTHING)

serializers.py

def save(self, request):
    # generate organization object
    organization_data = self.validated_data.pop('organization')
    organization = Organization.objects.create(**organization_data)
    self.validated_data['organization'] = organization

    adapter = get_adapter()
    user = adapter.new_user(request)
    self.cleaned_data = self.get_cleaned_data()
    user.organization = organization #self.cleaned_data.get('organization')
    adapter.save_user(request, user, self)
    self.custom_signup(request, user)
    setup_user_email(request, user, [])

    return user

Любое руководство высоко ценится.

Ответы [ 3 ]

2 голосов
/ 01 ноября 2019

Атомность является определяющим свойством транзакций базы данных. atomic позволяет нам создать блок кода, в котором гарантируется атомарность базы данных. Если блок кода успешно завершен, изменения фиксируются в базе данных. Если есть исключение, изменения отменяются.

from django.db import transaction

def viewfunc(request):
    # This code executes in autocommit mode (Django's default).
    do_stuff()

    with transaction.atomic():
        # This code executes inside a transaction.
        do_more_stuff()

для получения более подробной информации см. по указанной ссылке.

1 голос
/ 01 ноября 2019

Я хочу создать для них «организацию», если она не существует

Использовать Queryset.get_or_create, чтобы получить или создать организацию.

Оберните все это в транзакцию .

from django.db import transaction


with transaction.atomic():
    organization, created = Organization.objects.get_or_create(**organization_data)
    # Try creating user and if that fails, raise an Exception.
    # This way organisation created in the transaction is rolled back.
0 голосов
/ 01 ноября 2019

Вы должны добавить сигнал в вашу модель пользователя. вот так:

@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_organization(sender, instance=None, created=False, **kwargs):
    if created:
        organization.objects.create(user=instance)

это работа для меня. когда мне нужно создать какой-то объект, когда пользователь создал. он вызывается автоматически после создания пользовательского экземпляра.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...