问题
I am fairly new to Django and unfamiliar with the best practices for this situation (in any framework/language, not just python/django).
The situation is that when a user first registers on my site, I want to create an "organization" for them if it doesn't exists, and then subsequently create a user for them, which references the organization. I never want to insert one without the other, but I need to create the organization first so that the organization UUID can be saved for each user. Right now, organizations will still be created even if there is an issue with the creation of the user. This is obviously a problem because then I have an organization with no users attached.
I don't exactly know how to check that the user will be properly created before creating the organization, but something along these lines seems to be what I need to do. Using commit=false on the organization object creation wouldn't seem to work because I need to get the UUID. So I am not sure the best way to proceed.
I am overwriting the save method in the serializer of the popular authentication package 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
Any guidance is much appreciated.
回答1:
Atomicity is the defining property of database transactions. atomic allows us to create a block of code within which the atomicity on the database is guaranteed. If the block of code is successfully completed, the changes are committed to the database. If there is an exception, the changes are rolled back.
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()
for more detail refer to the given link.
回答2:
I want to create an "organization" for them if it doesn't exists
Use Queryset.get_or_create to get or create the organisation.
Wrap all of this in a transaction.
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.
回答3:
you must add signal into your user model . like this :
@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_organization(sender, instance=None, created=False, **kwargs):
if created:
organization.objects.create(user=instance)
this is work for me. when I need to create some object when the user created. it's called automatic after user instance created.
来源:https://stackoverflow.com/questions/58654790/create-object-only-if-other-object-is-successfully-created