-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
397 additions
and
125 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
# See: https://github.com/skorokithakis/django-annoying/blob/master/annoying/fields.py#L57 | ||
# This is a better alternative to signals | ||
import django | ||
from django.db.models import OneToOneField | ||
from django.db.transaction import atomic | ||
|
||
try: | ||
from django.db.models.fields.related_descriptors import ReverseOneToOneDescriptor | ||
except ImportError: | ||
from django.db.models.fields.related import SingleRelatedObjectDescriptor as ReverseOneToOneDescriptor | ||
|
||
|
||
class AutoSingleRelatedObjectDescriptor(ReverseOneToOneDescriptor): | ||
""" | ||
The descriptor that handles the object creation for an AutoOneToOneField. | ||
""" | ||
|
||
@atomic | ||
def __get__(self, instance, instance_type=None): | ||
model = getattr(self.related, "related_model", self.related.model) | ||
|
||
try: | ||
return super().__get__(instance, instance_type) | ||
except model.DoesNotExist: | ||
# Using get_or_create instead() of save() or create() as it better handles race conditions | ||
obj, _ = model.objects.get_or_create(**{self.related.field.name: instance}) | ||
|
||
# Update Django's cache, otherwise first 2 calls to obj.relobj | ||
# will return 2 different in-memory objects | ||
self.related.set_cached_value(instance, obj) | ||
self.related.field.set_cached_value(obj, instance) | ||
return obj | ||
|
||
|
||
class AutoOneToOneField(OneToOneField): | ||
""" | ||
OneToOneField creates related object on first call if it doesnt exist yet. | ||
Use it instead of original OneToOne field. | ||
example: | ||
class MyProfile(models.Model): | ||
user = AutoOneToOneField(User, primary_key=True) | ||
home_page = models.URLField(max_length=255, blank=True) | ||
icq = models.IntegerField(max_length=255, null=True) | ||
""" | ||
|
||
def contribute_to_related_class(self, cls, related): | ||
setattr(cls, related.get_accessor_name(), AutoSingleRelatedObjectDescriptor(related)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.