如何在 Django CreateView 中创建对象后添加指令?
How can I add an instruction after an object creation in Django CreateView?
在我基于 class 的通用 CreateView 上,我想执行一条指令,从与当前创建的对象相关的另一个模型创建新对象。
Example: Collection
is a model which is related to 3 differents Element
objects. When I create a MyCollection
object, which is related to a Collection
and a User
, 3 MyElement
object must be created too and related to the newly created MyCollection
object. One for each Element
related to Collection
.
# 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 中执行其他操作。
In my example, I did something similar:
# 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: Generic detail view MyCollectionCreateView must be called with either an object pk or a slug in the URLconf.
我不明白为什么。
我的 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: Generic detail view MyCollectionCreateView must be called with either an object pk or a slug in the URLconf.
编辑 2
通过从 MyCollectionCreateView
class 中删除 get_absolute_url()
覆盖,它确实有效。很好,但我仍然想知道问题出在哪里。如果这解决了问题,可能是我没看到的愚蠢行为。
# 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 ...
get_absolute_url()
在为模型创建新实例时使用,因为 django 必须知道在创建新 post 或创建新实例时去哪里。
来自错误
AttributeError: Generic detail view MyCollectionCreateView must be called with either an object pk or a slug in the URLconf.
它告诉您必须使用 object pk
或 slug
来调用它,因此您构建的 URL 就是问题所在。我不确定这种方法 create_myelements_for_mycollection()
是否满足这种需要。
理想情况下,您需要的是
def get_absolute_url(self):
return f"/mycollection/{self.slug}/"
生成上述模式中的 URL
,例如在锚标记中使用。
在我基于 class 的通用 CreateView 上,我想执行一条指令,从与当前创建的对象相关的另一个模型创建新对象。
Example:
Collection
is a model which is related to 3 differentsElement
objects. When I create aMyCollection
object, which is related to aCollection
and aUser
, 3MyElement
object must be created too and related to the newly createdMyCollection
object. One for eachElement
related toCollection
.
# 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 中执行其他操作。
In my example, I did something similar:
# 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: Generic detail view MyCollectionCreateView must be called with either an object pk or a slug in the URLconf.
我不明白为什么。
我的 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: Generic detail view MyCollectionCreateView must be called with either an object pk or a slug in the URLconf.
编辑 2
通过从 MyCollectionCreateView
class 中删除 get_absolute_url()
覆盖,它确实有效。很好,但我仍然想知道问题出在哪里。如果这解决了问题,可能是我没看到的愚蠢行为。
# 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 ...
get_absolute_url()
在为模型创建新实例时使用,因为 django 必须知道在创建新 post 或创建新实例时去哪里。
来自错误
AttributeError: Generic detail view MyCollectionCreateView must be called with either an object pk or a slug in the URLconf.
它告诉您必须使用 object pk
或 slug
来调用它,因此您构建的 URL 就是问题所在。我不确定这种方法 create_myelements_for_mycollection()
是否满足这种需要。
理想情况下,您需要的是
def get_absolute_url(self):
return f"/mycollection/{self.slug}/"
生成上述模式中的 URL
,例如在锚标记中使用。