Django-使用通用UpdateView编辑多对多关系的两端 [英] Django - edit both sides of a many-to-many relation with generic UpdateView

查看:107
本文介绍了Django-使用通用UpdateView编辑多对多关系的两端的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个问题,是否可以使用通用的UpdateView类来编辑多对多关系的双方。
我在models.py中定义了以下类:

I have a question whether or not it is possible to use the generic UpdateView class to edit "both sides" of a many-to-many relationship. I have the following classes defined in 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:

These are both dictionary type tables that store sets of configuration data for my application. To allow editing the dictionaries I use simple UpdateViews:

class SomeClassUpdate(UpdateView):
    model = SomeClass
    template_name = 'admin/edit_class.html'
    fields = ['code', 'name', 'age', 'allowed_categories']
    ordering = ['code']

这很好,我得到了不错的选择,一切都很完美。但是,我希望可以从SomeCategory表的一侧编辑关系,因此我可以选择将SomeClass元素链接到某个SomeCategory:

This works fine, I get a nice multi-select and everything is perfect. However, I would like to have the possibility to edit the relationship from the side of the SomeCategory table, so I can choose which SomeClass elements are linked to a certain SomeCategory:

class SomeCategoryUpdate(UpdateView):
    model = SomeCategory
    template_name = 'admin/edit_category.html'
    fields = ['code', 'name',  ??????? ]
    ordering = ['code']

我尝试添加 related_name 属性添加到SomeCategory模型,但这无效。

I have tried adding the related_name attribute to the SomeCategory model, but that did not work.

有什么想法可以在不使用自定义ModelForm的情况下完成?

Any ideas if this can be done without using a custom ModelForm?

密钥库版本:

Django==1.11.8
psycopg2==2.7.4

PS:这是我对stackoverflow的第一个问题,所以请让我知道我的帖子是否缺少任何必填元素。

PS: this is my very first question asked on stackoverflow, so please let me know if my post is missing any mandatory elements.

推荐答案

您的问题在models.py文件中。您有两个班级,但其中只有一个班级提到另一班。您可能认为这应该足够了,因为您毕竟使用的是 ManyToManyField 并假定它将自动创建双向的每个连接...不幸的是,这不是事实。在数据库级别,确实确实创建了一个单独的中间表,其中引用了两个原始表中的对象,但这并不意味着它们都将在Django Admin或类似版本中自动显示。

Your issue is in the models.py file. You have two classes, but only one of them mentions the other one. You would think that this should be enough since you are using ManyToManyField after all and assume that it would automatically create every connection leading both ways... Unfortunately this is not true. On the database level it does indeed create a separate intermediary table with references to objects in both original tables, but that doesn't mean that both of them will be automatically visible in Django Admin or similar.

如果您尝试简单地在 SomeCategory someclass = models.ManyToManyField(SomeClass) >将会失败的类。 Django会尝试创建另一个独立的中介表,通过建立两个主表之间的连接。但是由于中间表的名称取决于定义 ManyToManyField 连接的位置,因此第二个表将使用不同的名称创建,并且所有内容在逻辑上都将折叠(两个表具有两种具有多对多连接的默认方法没有任何意义)。

If you would attempt to simply create another someclass = models.ManyToManyField(SomeClass) in the SomeCategory class that would fail. Django would try to create another separate intermediary table through which the connection between two main tables is established. But because the name of the intermediary table depends on where you define the ManyToManyField connection, the second table would be created with a different name and everything would just logically collapse (two tables having two separate default ways to have a ManyToMany connection makes no sense).

解决方案是将 ManyToManyField 连接添加到 SomeCategory 还引用了最初在 SomeClass 类中创建的中介/穿透表。

The solution is to add a ManyToManyField connection to SomeCategory while also referencing that intermediary/through table that was originally created in the SomeClass class.

一些注意事项关于Django / python / naming / programming约定:

A couple of notes about Django/python/naming/programming conventions:


  • 使用您要引用的表的名称作为该字段的名称包含有关该连接的信息。这意味着 SomeClass 的具有 SomeCategory 链接的字段应命名为 somecategory 而不是 allowed_categories

  • 如果连接是一对多-使用单数形式;如果连接是多对多-使用复数。意味着在这种情况下,我们应该使用复数并使用 somecategories 而不是 somecategory

  • Django可以自动将名称复数,但是这样做很糟糕-它只是在末尾添加 s 字母。 鼠标-> 鼠标类别-> 类别。在这种情况下,您必须通过在特殊的 Meta 类中定义 verbose_name_plural 来提供帮助。

  • 仅在代码中先前已经定义了该类的情况下,才使用对其他类的引用而无需额外的'。在两个类相互引用的情况下,这仅是一种方式。解决方案是将引用类的名称放在引号中,例如 SomeCategory ,而不是 SomeCategory 。这种引用称为惰性关系,在解决两个应用程序之间的循环导入依赖关系时很有用。而且由于默认情况下最好保持样式相同,避免不必要的浪费精力,我将根据课程的组织顺序来决定是否使用引号;我将不得不重做该引号每次我决定移动一些代码段时,我建议您每次都只使用引号。就像在学习驾驶汽车时一样,最好学会始终使用转向信号灯,而不是先环顾四周并做出是否有人会从该信息中受益的单独决定。

  • 字符串化(延迟加载)模型/类/表的名称很容易-只需添加'即可。您可能会认为,对通过表引用进行字符串化将以相同的简便方式工作。而且您会错的-它会为您提供 ValueError:无效的模型引用。字符串模型引用的格式必须为 app_label.ModelName。错误。为了引用字符串化的直通表格,您需要:(a)在 周围添加; (b)将所有点()替换为下划线( _ ); (c)删除对 through !的引用。.因此, SomeClass.somecategories.through 变为 'SomeClass_somecategories'

  • Use the name of the table you are referencing to, as the name of the field that is containing the info about that connection. Meaning that SomeClass's field with a link to SomeCategory should be named somecategory instead of allowed_categories.
  • If the connection is one-to-many - use singular form; if the connection is many-to-many - use plural. Meaning that in this case we should use plural and use somecategories instead of somecategory.
  • Django can automatically pluralize names, but it does it badly - it simply adds s letter to the end. Mouse -> Mouses, Category -> Categorys. In those kind of cases you have to help it by defining the verbose_name_plural in the special Meta class.
  • Using references to other classes without extra 's works only if the the class was already defined previously in the code. In the case of two classes referring to each other that is true only one way. The solution is to put the name of the referred class in the quotation marks like 'SomeCategory' instead of SomeCategory. This sort of reference, called a lazy relationship, can be useful when resolving circular import dependencies between two applications. And since by default it's better to keep the style the same and to avoid unnecessary brain energy wasting of "I will decide whether or not to use quotation marks depending on the order the classes have been organized; I will have to redo this quotation marks thingie every time I decide to move some code pieces around" I recommend that you simply use quotation marks every time. Just like when learning to drive a car - it's better to learn to always use turn signals instead of first looking around and making a separate decision of whether someone would benefit from that information.
  • "Stringifying" (lazy loading) model/class/table name is easy - just add 's around. You would think that stringifying the "through" table reference would work the same easy way. And you would be wrong - it will give you the ValueError: Invalid model reference. String model references must be of the form 'app_label.ModelName'. error. In order to reference the stringified "through" table you need to: (a) add 's around; (b) replace all dots (.) with underscores (_); (c) delete the reference to through!.. So SomeClass.somecategories.through becomes 'SomeClass_somecategories'.

因此解决方案是这样的:

Therefore the solution is this:

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 类进行什么样的最终更改。

After this it should be obvious what kind of final changes to make to your UpdateView classes.

这篇关于Django-使用通用UpdateView编辑多对多关系的两端的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆