Admin inlines linked indirectly by a shared UUID instead of by foreign key
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:
class AttachmentForm(django.forms.ModelForm):
def save(self, *args, **kwargs):
obj = super(AttachmentForm, self).save(*args, **kwargs)
obj.nonce = self.instance.nonce
if kwargs.get('commit', True):
obj.save()
return obj
Exclude the nonce field from the inline:
class AttachmentInline(admin.TabularInline):
exclude = ['nonce']
model = Attachment
form = AttachmentForm
Come up with a new nonce for a new post:
class PostAdminForm(django.forms.ModelForm):
def __init__(self, *args, **kwargs):
super(PostAdminForm, self).__init__(*args, **kwargs)
self.initial.setdefault('nonce', S3File.get_unique_nonce())
Use the inline:
# A particular kind of post
class FooPostAdmin(admin.ModelAdmin):
form = PostAdminForm
inlines = [AttachmentInline]
精彩评论