I'm reading a book about Django and I'm trying to reinterpret some content. (I'm using Django 2.1 and Python 3.6) In the book different types of contents are associated with a module, like this:
class Module(models.Model):
course = models.ForeignKey(Course,
related_name='modules',
on_delete=models.CASCADE)
title = models.CharField(max_length=200)
description = models.TextField(blank=True)
order = OrderField(blank=True, for_fields=['course'])
class Meta:
ordering = ['order']
def __str__(self):
return '{}. {}'.format(self.order, self.title)
class Content(models.Model):
module = models.ForeignKey(Module,
related_name='contents',
on_delete=models.CASCADE)
content_type = models.ForeignKey(ContentType,
on_delete=models.CASCADE,
limit_choices_to={'model__in': (
'text',
'video',
'image',
'file')})
object_id = models.PositiveIntegerField()
item = GenericForeignKey('content_type', 'object_id')
order = OrderField(blank=True, for_fields=['module'])
class Meta:
ordering = ['order']
class ItemBase(models.Model):
owner = models.ForeignKey(User,
related_name='%(class)s_related',
on_delete=models.CASCADE)
title = models.CharField(max_length=250)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
def __str__(self):
return self.title
def render(self):
return render_to_string(
'courses/content/{}.html'.format(self._meta.model_name),
{'item': self})
class Text(ItemBase):
content = models.TextField()
class File(ItemBase):
file = models.FileField(upload_to='files')
class Image(ItemBase):
file = models.FileField(upload_to='images')
class Video(ItemBase):
url = models.URLField()
In the book there are CBVs to generate the right form for content types:
class ContentCreateUpdateView(TemplateResponseMixin, View):
module = None
model = None
obj = None
template_name = 'courses/manage/content/form.html'
def get_model(self, model_name):
if model_name in ['text', 'video', 'image', 'file']:
return apps.get_model(app_label='courses',
model_name=model_name)
return None
def get_form(self, model, *args, **kwargs):
Form = modelform_factory(model, exclude=['owner',
'order',
'created',
'updated'])
return Form(*args, **kwargs)
def dispatch(self, request, module_id, model_name, id=None):
self.module = get_object_or_404(Module,
id=module_id,
course__owner=request.user)
self.model = self.get_model(model_name)
if id:
self.obj = get_object_or_404(self.model,
id=id,
owner=request.user)
return super(ContentCreateUpdateView,
self).dispatch(request, module_id, model_name, id)
def get(self, request, module_id, model_name, id=None):
form = self.get_form(self.model, instance=self.obj)
return self.render_to_response({'form': form,
'object': self.obj})
def post(self, request, module_id, model_name, id=None):
form = self.get_form(self.model,
instance=self.obj,
data=request.POST,
files=request.FILES)
if form.is_valid():
obj = form.save(commit=False)
obj.owner = request.user
obj.save()
if not id:
# new content
Content.objects.create(module=self.module,
item=obj)
return redirect('module_content_list', self.module.id)
return self.render_to_response({'form': form,
'object': self.obj})
And contents are provided by users with special permissions. Ok and now the question: I want the contents to be managed only by the admin, in the admin site. I've tried this way:
class ContentInline(GenericStackedInline):
model = Content
extra = 0
@admin.register(Module)
class ModuleAdmin(admin.ModelAdmin):
list_display = ['title', 'order', 'course']
list_filter = ['course']
search_fields = ['title', 'description']
inlines = [ContentInline]
@admin.register(Content)
class ContentAdmin(admin.ModelAdmin):
list_display = ['object_id', 'module', 'content_type', 'order']
but I have not been able to display in the admin site forms the field to upload the right content type. Module page looks like this:
While Content page is this:
I've been searching for a solution for a while but I've not been able to find one. There is a similar topic here: link but suggested solutions imply javascript and/or additional packages while I'd like to do that only with Python and Django.
I've also read that a possible solution to display custom views in admin site is to write a view and then add it to the admin urls, then add it to the admin model.
Someone else suggested to use CBV from the book and use it in model admin.
I've tried to implement these suggestions with no luck.
In the last version of my code I try to use the CBV with as_view()
this way (in views.py right after CBV):
content_create_update_view = ContentCreateUpdateView.as_view()
and then in admin.py:
@admin.register(Content)
class ContentAdmin(admin.ModelAdmin):
list_display = ['object_id', 'module', 'content_type', 'order']
def get_urls(self):
urls = super().get_urls()
my_urls = [
path('content/<int:object_id>/change/', self.admin_site.admin_view(content_create_update_view)),
]
return my_urls + urls
any help or suggestion is greatly appreciated.