(1) Okay let me then summarize the syntaxes in async context that are the best candidates so far:
- Single-Model Returning Methods
await objects.filter(...).order_by(...).first_async()
await Question.objects.get_async(id=...)
- Multiple-Model Returning Methods
choices = await question.choice_set.all_async() # need not be prefetched
choices = question.choice_set.all() # raises if not prefetched
- Model Field Get
q = await choice.question_async
- Model Field Set (Deferred)
choice.question = q
- Single-Model Save
await question.save_async()
- Multiple-Model Save
await choice_set.update_async(...)
await bulk_update_async(...)
await bulk_create_async(...)
(2) A user who creates their own model class which overrides save
who wants their model to also be used in an async context should also override save_async
:
class ProjectTextFile(models.Model):
name = models.CharField(max_length=50)
content = models.TextField(blank=True)
def save(self, *args, **kwargs):
if ProjectTextFile.is_content_too_big(self.name, self.content):
raise ValidationError(...)
super().save(*args, **kwargs)
async def save_async(self, *args, **kwargs):
if ProjectTextFile.is_content_too_big(self.name, self.content):
raise ValidationError(...)
await super().save_async(*args, **kwargs)
If only one of save
or save_async
is overridden, I’d have to think more about the consequences…
- The built-in
admin
app currently would always use the synchronoussave
and ignore anysave_async
. - User code that was familiar with the model class would presumably invoke whichever save method was implemented.
(3) It feels a bit weird to have a method’s return type vary depending on whether it is being invoked from a sync context vs. an async context, but perhaps it could work…
I could see this trick working for methods like .get()
and .save()
. For model fields the getter would have to return a proxy if invoked from an async context, but the setter would continue to defer any actual set operation regardless of whether it is invoked from a sync/async context.
(4) Ick. Inspecting the current stack frame is almost certainly quite slow. Better stick with querying the event loop.