我有一个问题,是否可以使用通用的UpdateView类来编辑多对多关系的“双方”。 我在models.py中定义了以下类:
class SomeCategory(models.Model):
code = models.CharField(max_length=5)
name = models.CharField(max_length=40)
class SomeClass(models.Model):
code = models.CharField(max_length=3, unique=True)
name = models.CharField(max_length=30, unique=False)
age = models.IntegerField(null=False)
allowed_categories = models.ManyToManyField(SomeCategory)
这两个都是字典类型表,用于存储我的应用程序的配置数据集。为了允许编辑字典,我使用简单的UpdateViews:
class SomeClassUpdate(UpdateView):
model = SomeClass
template_name = 'admin/edit_class.html'
fields = ['code', 'name', 'age', 'allowed_categories']
ordering = ['code']
这很好,我得到了不错的选择,一切都完美。但是,我希望可以从SomeCategory表的一侧编辑关系,因此我可以选择将哪些SomeClass元素链接到某个SomeCategory:
class SomeCategoryUpdate(UpdateView):
model = SomeCategory
template_name = 'admin/edit_category.html'
fields = ['code', 'name', ??????? ]
ordering = ['code']
我尝试将related_name
属性添加到SomeCategory模型中,但这没有用。
任何想法都可以在不使用自定义ModelForm的情况下完成吗?
密钥库版本:
Django==1.11.8
psycopg2==2.7.4
PS:这是我关于stackoverflow的第一个问题,所以请让我知道我的帖子是否缺少任何必填元素。
答案 0 :(得分:1)
您的问题在models.py文件中。您有两个班级,但是其中只有一个班级提到另一班。您可能认为这应该足够了,因为您毕竟使用ManyToManyField
并假定它将自动创建双向引导的每个连接...不幸的是,事实并非如此。在数据库级别上,确实确实创建了一个单独的中间表,并引用了两个原始表中的对象,但这并不意味着它们在Django Admin或类似程序中都将自动可见。
如果您尝试简单地在someclass = models.ManyToManyField(SomeClass)
类中创建另一个SomeCategory
,那将会失败。 Django会尝试通过通过创建另一个单独的中介表,以在两个主表之间建立连接。但是,由于中间表的名称取决于您定义ManyToManyField
连接的位置,因此第二个表将使用不同的名称创建,并且所有内容在逻辑上都将折叠(两个表具有两个单独的 default >建立ManyToMany连接的方法没有任何意义)。
解决方案是向ManyToManyField
添加一个SomeCategory
连接,同时还要引用最初在SomeClass
类中创建的中介/穿透表。
关于Django / python / naming / programming约定的一些注释:
SomeClass
的链接到SomeCategory
的字段应命名为somecategory
而不是allowed_categories
。somecategories
而不是somecategory
。s
字母。 Mouse
-> Mouses
,Category
-> Categorys
。在这种情况下,您必须通过在特殊的verbose_name_plural
类中定义Meta
来提供帮助。'
。在两个类相互引用的情况下,这仅是一种方法。解决方案是将引用类的名称放在引号内,例如'SomeCategory'
而不是SomeCategory
。这种引用称为lazy relationship
的引用在解决两个应用程序之间的循环导入依赖关系时很有用。而且由于默认情况下最好保持样式相同,并避免不必要的“浪费精力”,“我将根据课程的组织顺序来决定是否使用引号;我将不得不重做该引号”每次我决定移动一些代码段时,“我建议您每次都只使用引号。就像在学习驾驶汽车时一样,最好学会始终使用转向信号灯,而不是先环顾四周并做出是否有人从该信息中受益的单独决定。'
即可。您可能会认为,对“通过”表引用进行字符串化将以相同的简单方式工作。而且你会错的-它会给你ValueError: Invalid model reference. String model references must be of the form 'app_label.ModelName'.
错误。为了引用字符串化的“通过”表,您需要:(a)在周围添加'
; (b)用下划线(.
)替换所有点(_
); (c)删除对through
的引用!。因此SomeClass.somecategories.through
变成'SomeClass_somecategories'
。因此解决方案是这样:
class SomeCategory(models.Model):
code = models.CharField(max_length=5)
name = models.CharField(max_length=40)
someclasses = models.ManyToManyField('SomeClass', through='SomeClass_somecategories', blank=True)
class Meta:
verbose_name_plural = 'SomeCategories'
class SomeClass(models.Model):
code = models.CharField(max_length=3, unique=True)
name = models.CharField(max_length=30, unique=False)
age = models.IntegerField(null=False)
somecategories = models.ManyToManyField('SomeCategory')
在此之后,应该很明显地对UpdateView
类进行什么样的最终更改。