首页 > 解决方案 > 如何在 Django CreateView 中创建对象后添加指令?

问题描述

在基于通用类的 CreateView 上,我想执行一条指令,该指令从与当前创建的对象相关的另一个模型创建新对象。

示例:Collection是与 3 个不同Element对象相关的模型。当我创建一个与 a和 aMyCollection相关的对象时,也必须创建3 个对象并与新创建的对象相关。每个与 相关的一个。CollectionUserMyElementMyCollectionElementCollection

# models.py

from django.contrib.auth.models import User
from django.db import models


class Collection(models.Model):
    # attributes and methods...


class Element(models.Model):
    collection = models.ForeignKey(Collection, # more arguments...)
    # more attributes and methods


class MyCollection(models.Model):
    user = models.ForeignKey(User, # more arguments...)
    collection = = models.ForeignKey(Collection, # more arguments...)
    # more attributes and methods

    def get_absolute_url(self):
        reverse(# some url with the object pk)


class MyElement(models.Model):
    element = models.ForeignKey(Element, # more arguments...)
    my_collection = models.ForeignKey(MyCollection, # more arguments...)
    # more attributes and methods

我正在使用来自 Django 的通用 CreateView,经过一些研究,我发现可以通过覆盖 get_success_url() 方法在 CreateView 中执行其他操作。

在我的示例中,我做了类似的事情:

# views.py

from django.views.generic import CreateView

from .utils import create_myelements_for_mycollection


class MyCollectionCreateView(CreateView):
    model = MyCollection
    # more attributes and methods...

    def get_success_url(self):
        create_myelements_for_mycollection(self.get_object())  # Here is where the bug occurs, works fine without this line

        return super().get_success_url()
# utils.py

from .models import Collection, Element, MyCollection, MyElement


def create_myelements_for_mycollection(my_collection):
    for element in my_collection.collection.elements_set.all():
        MyElement.objects.create(
            element=element,
            my_collection=my_collection,
        )
# urls.py

from django.urls import re_path

from . import views


urlpatterns = [
    re_path(
        r"^myelement/l/$",
        views.MyElementListView.as_view(),
    ),
    re_path(
        r"^myelement/r/(?P<pk>[0-9]+)/$",
        views.MyElementDetailView.as_view(),
    ),
    re_path(
        r"^myelement/c/(?P<element_pk>\d+)/$",
        views.MyElementCreateView.as_view(),
    ),

    re_path(
        r"^mycollection/l/$",
        views.MyCollectionListView.as_view(),
    ),
    re_path(
        r"^mycollection/r/(?P<pk>[0-9]+)/$",
        views.MyCollectionDetailView.as_view(),
    ),
    re_path(
        r"^mycollection/c/(?P<collection_pk>\d+)/$",
        views.MyCollectionCreateView.as_view(),
    ),
]

当我创建一个新MyCollection对象时,所有对象都MyElements在数据库中成功创建,但出现此错误:

AttributeError:必须使用 URLconf 中的对象 pk 或 slug 调用通用详细视图 MyCollectionCreateView。

我不明白为什么。

我的 CreateView url 没有任何 pk,因为当您创建新对象时,它还没有 pk。还有,MyCollection有自己的get_absolute_url。没有那个具体的指示,我工作得很好。

有人可以解释一下导致错误的原因吗?在创建对象后是否有更好的方法来执行这样的指令?

谢谢您的帮助。

FYI:

Django 3.1
Pyhton 3.8

编辑

我尝试改用 post_save 信号(实际上写起来更干净),但我遇到了完全相同的错误。

# models.py

from django.db.models.signals import post_save
from django.dispatch import receiver

from .utils import create_myelements_for_mycollection


# ...models

@receiver(post_save, sender=MyCollection)
def create_myelements_for_mycollection(sender, instance, **kwargs):

    if instance is created:  # ? (Didn't look at how to write this condition in a signal yet)
        create_myelements_for_mycollection(my_collection)

AttributeError:必须使用 URLconf 中的对象 pk 或 slug 调用通用详细视图 MyCollectionCreateView。

编辑 2

通过从类中删除get_absolute_url()覆盖MyCollectionCreateView,它实际上可以工作。这很好,但我仍然想知道问题是什么。如果这解决了问题,可能我没有看到一些愚蠢的东西。

# models.py

# ... previous code

class MyCollectionCreateView(CreateView):
    model = MyCollection
    # more attributes and methods...

    # Removing this solved the issue
    # def get_success_url(self):
    #     create_myelements_for_mycollection(self.get_object())
    #
    #     return super().get_success_url()

# more code ...

标签: pythondjangocreate-view

解决方案


get_absolute_url()在为模型创建新实例时使用,因为当创建新帖子或创建新实例时,django 必须知道去哪里。

从错误

AttributeError:必须使用 URLconf 中的对象 pk 或 slug 调用通用详细视图 MyCollectionCreateView。

它告诉您必须使用 aobject pk或 a调用它slug,因此您对 URL 的构造是问题所在。我不确定该方法是否create_myelements_for_mycollection()满足这种需求。

理想情况下,您需要的是类似的东西,例如

def get_absolute_url(self):
    return f"/mycollection/{self.slug}/"

生成URL上述模式中的,例如在锚标记中使用。


推荐阅读