I have posts and attachments. The source of my problem is that I would like it to be possible to create attachments before creating the post they are attached to (because the user uses the fancy Ajax upload widget to upload the attachment before filling out the details of the post). The solution I have arrived at is to give each post a UUID. The UUID is generated when the post’s modelform is instantiated (i.e., before creating the post). When attachments are uploaded, they are associated with this UUID. Before I pose my question, here is a sketch of the code in order to show more precisely what is going on:
# models.py
import uuid
from django.db import models
class Post(models.Model):
nonce = models.CharField(max_length=36)
class FooPost(Post):
body = models.TextField()
class UploadedFile(models.Model):
url = models.URLField(max_length=1024)
nonce = models.CharField(max_length=36)
@classmethod
def get_unique_nonce(cls):
while True:
nonce = str(uuid.uuid4())
if not cls.objects.filter(nonce=nonce).exists():
return nonce
class Attachment(UploadedFile):
post = models.ForeignKey(Post)
# views.py
class FooPostForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(PostForm, self).__init__(*args, **kwargs)
self.initial.setdefault('uuid', UploadedFile.get_unique_uuid())
def save(self, *args, **kwargs):
obj = super(FooPostForm, self).save(*args, **kwargs)
if kwargs.get('commit', True):
for file in UploadedFile.objects.filter(nonce=obj.nonce)
Attachment(uploadedfile_ptr=file, post=obj).save_base(raw=True)
return obj
class Meta:
model = FooPost
def foo_post(request):
assert request.method == 'POST'
form = FooPostForm(request.POST)
if form.is_valid():
post = form.save()
# ...
This works well in my app, but I would like it to also work in the admin interface. How can I inline the attachments in the admin form for the post, even though they are linked indirectly by shared nonce instead of by a foreign key?
Provide a custom modelform for the inline:
Exclude the nonce field from the inline:
Come up with a new nonce for a new post:
Use the inline: