简体   繁体   English

Django Admin 通用内容类型多模型内联表单

[英]Django Admin Generic content type multiple models inline form

I'm getting started with Django and I'm a bit stuck on a multi-models field, AKA Generic Relation (Content Type)我刚开始使用 Django,但在多模型领域(AKA Generic Relation(内容类型))上有点卡住了

I have a generic content type "student_solution" that can belong to either:我有一个通用的内容类型“student_solution”,它可以属于:

  • a Org model Org模型
  • a Institution model Institution模式
  • a Campus model Campus模式

Therefore, in each of those 3 models, I have a reversed relationship as follow, in each models.py :因此,在这 3 个模型中的每一个中,我在每个models.py中都有如下相反的关系:

# Reverse generic relation - XXX See https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/#reverse-generic-relations
student_solutions = GenericRelation('student_solution.StudentSolution')

I'm not sure whether this is the right approach, I think so, but a confirmation is welcome :)我不确定这是否是正确的方法,我认为是这样,但欢迎确认:)


It's working fine as it is now, but it's not user-friendly in the Django Admin UI, see how it display on django admin, when creating a Student Solution (I would expect a select box showing a label field, instead of entering the Content Type ID by hand):它现在工作正常,但它在 Django Admin UI 中不是用户友好的,看看它如何在 django admin 上显示,在创建学生解决方案时(我希望选择框显示label字段,而不是输入内容手动输入 ID):

Django 管理员创建实体

When creating either an Org, Institution or Campus, the field doesn't show at all in the Django Admin (so I probably misconfigured something)创建组织、机构或校园时,该字段根本不显示在 Django 管理中(所以我可能配置错误)

I tried following How to replace content_type and object_id fields by a field with actual object in admin inline?我尝试了如何通过内联管理中的实际对象的字段替换 content_type 和 object_id 字段? to improve the UI by allowing to select the right Content Type and "object" using the object's label.通过允许使用对象的标签选择正确的内容类型和“对象”来改进 UI。 But it doesn't work at this time.但此时它不起作用。


student_solution/models.py : student_solution/models.py

from django.contrib.contenttypes import fields
from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.db.models import Q
from jsonfield import JSONField

from tfp_backoffice.apps.institution.models import Institution

CONTENT_TYPE_CHOICES = (
  Q(app_label='org', model='org') |
  Q(app_label='institution', model='institution') |
  Q(app_label='campus', model='campus')
)

class StudentSolution(models.Model):
  # Dynamic relationship to either Org, Institution or Campus entities
  # XXX https://simpleisbetterthancomplex.com/tutorial/2016/10/13/how-to-use-generic-relations.html
  content_type = models.ForeignKey(
    ContentType,
    on_delete=models.CASCADE,  # TODO check if good thing
    limit_choices_to=CONTENT_TYPE_CHOICES,
  )
  object_id = models.PositiveIntegerField()
  content_object = fields.GenericForeignKey(
    'content_type',
    'object_id'
  )

student_solution/admin.py : student_solution/admin.py

from django.contrib import admin
from modeltranslation.admin import TranslationAdmin

from tfp_backoffice.apps.org.models import Org
from tfp_backoffice.apps.student_solution.forms import StudentSolutionAdminForm, GenericStudentSolutionOwnerChoicesFieldForm
from tfp_backoffice.apps.student_solution.models import StudentSolution

    
class StudentSolutionInlineAdmin(admin.TabularInline):
  form = GenericStudentSolutionOwnerChoicesFieldForm
  model = Org  # TODO not sure at all about that, should be either of 3 related ContentTypes (Org | Institution | Campus)
  # This throw error "<class 'tfp_backoffice.apps.student_solution.admin.StudentSolutionInlineAdmin'>: (admin.E202) 'org.Org' has no ForeignKey to 'student_solution.StudentSolution'."


class StudentSolutionAdmin(TranslationAdmin):
  form = StudentSolutionAdminForm
  inlines = [
    StudentSolutionInlineAdmin,
  ]


admin.site.register(StudentSolution, StudentSolutionAdmin)

student_solution/forms.py : student_solution/forms.py

from django import forms
from django.contrib.contenttypes.models import ContentType

from tfp_backoffice.apps.org.models import Org
from tfp_backoffice.apps.student_solution.models import CONTENT_TYPE_CHOICES, StudentSolution


class StudentSolutionAdminForm(forms.ModelForm):
  class Meta:
    model = StudentSolution
    fields = '__all__'  # Keep all fields    

class GenericStudentSolutionOwnerChoicesFieldForm(forms.ModelForm):
  ct_place_type = ContentType.objects.get_for_model(Org)  # TODO not sure at all about that, should be either of 3 related ContentTypes (Org | Institution | Campus)

  object_id = forms.ModelChoiceField(
    Org.objects.all(),
    limit_choices_to=CONTENT_TYPE_CHOICES,
    label='Student solution'
  )
  content_type = forms.ModelChoiceField(
    ContentType.objects.all(),
    initial=ct_place_type,  
    limit_choices_to=CONTENT_TYPE_CHOICES,  # should I use this here?
    widget=forms.HiddenInput()
  )

  def clean_object_id(self):
    return self.cleaned_data['object_id'].pk

  def clean_content_type(self):
    return self.ct_place_type

But this code isn't working and throw this error when starting the server但是此代码不起作用并在启动服务器时抛出此错误

django.core.management.base.SystemCheckError: SystemCheckError: System check identified some issues: django.core.management.base.SystemCheckError: SystemCheckError: 系统检查发现了一些问题:

<class 'tfp_backoffice.apps.student_solution.admin.StudentSolutionInlineAdmin'>: (admin.E202) 'org.Org' has no ForeignKey to 'student_solution.StudentSolution'.

If I am understanding what you would like to do correctly you should have your StudentSolutionInlineAdmin in each of the Org , Institution , and Campus admins and it should be a GenericTabularInline ( https://docs.djangoproject.com/en/2.2/ref/contrib/contenttypes/#generic-relations-in-admin ).如果我理解您想要正确执行的操作,您应该在每个OrgInstitutionCampus管理员中都有您的StudentSolutionInlineAdmin ,它应该是一个GenericTabularInline ( https://docs.djangoproject.com/en/2.2/ref/ contrib/contenttypes/#generic-relations-in-admin )。

So you would have something like this in (for example) your org/admin.py :所以你会在(例如)你的org/admin.py有这样的东西:

from django.contrib import admin
from django.contrib.contenttypes.admin import GenericTabularInline
from django import forms

from .models import Org
from student_solution.models import StudentSolution

class StudentSolutionInlineAdmin(GenericTabularInline):
    model = StudentSolution
    extra = 1

class StudentSolutionAdminForm(forms.ModelForm):
    class Meta:
        model = StudentSolution
        fields = '__all__'  # Keep all fields 

@admin.register(Org)
class OrgAdmin(admin.ModelAdmin):
    form = StudentSolutionAdminForm
    inlines = [StudentSolutionInlineAdmin]

This will allow you to add a StudentSolution related to an Org from within the Org admin.这将允许您从Org管理员中添加与Org相关的 StudentSolution。

You could have a look on this one: https://docs.djangoproject.com/en/2.2/ref/contrib/contenttypes/#generic-relations-in-admin你可以看看这个: https : //docs.djangoproject.com/en/2.2/ref/contrib/contenttypes/#generic-relations-in-admin

They have special inline types to use if you are using the content type feature framework如果您使用的是内容类型功能框架,它们有特殊的内联类型可供使用

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM