Django get_model() 模型没有属性 'objects'
Django get_model() model has no attribute 'objects'
我正在写一个迁移来更新数据,我像文档描述的那样使用 get_model() 来获取模型 class,如下所示:
from django.db import migrations
def update_student(apps, schema_editor):
# We can't import the model directly as it may be a newer
# version than this migration expects. We use the historical version.
CourseClass = apps.get_model('backend', 'CourseClass')
from pprint import pprint
pprint(vars(CourseClass))
for course_class in CourseClass.objects.all():
if course_class.course:
if course_class.course.student:
course_class.students.add(course_class.course.student)
Course = apps.get_model('backend', 'Course')
for course in Course.objects.all():
if course.student:
course.students.add(course.student)
class Migration(migrations.Migration):
dependencies = [
('backend', '0199_auto_20211027_1026'),
]
operations = [
migrations.RunPython(update_student, migrations.RunPython.noop)
]
这是我的模型和一些自定义管理器:
class CourseClass(models.Model):
class Meta:
db_table = 'classes'
verbose_name = _('Class')
verbose_name_plural = _('Classes')
student_manager = StudentManager()
teacher_manager = TeacherManager()
objects = models.Manager()
# other fields
当 运行 我的迁移时,我收到以下错误:
File "/Users/admin/Library/Caches/pypoetry/virtualenvs/base.django-AnqsdXoZ-py3.8/lib/python3.8/site-packages/django/db/migrations/operations/special.py", line 190, in database_forwards
self.code(from_state.apps, schema_editor)
File "/Users/admin/Documents/git/icts/vietphil.hoola/backend/migrations/0200_update_student.py", line 13, in update_student
for course_class in CourseClass.objects.all():
AttributeError: type object 'CourseClass' has no attribute 'objects
使用 pprint return 打印 CourseClass 的属性如下:
mappingproxy({'DoesNotExist': <class '__fake__.CourseClass.DoesNotExist'>,
'MultipleObjectsReturned': <class '__fake__.CourseClass.MultipleObjectsReturned'>,
'__doc__': 'CourseClass(id, name, date, time, duration, course, '
'substitute_teacher, delay_from, status, over, '
'class_type, canceled_by, note, teacher, '
'datetimestart, real_duration, screen_share, '
'time_end, time_start, extra_course)',
'__module__': '__fake__',
'_meta': <Options for CourseClass>,
'assignment_class': <django.db.models.fields.related_descriptors.ReverseOneToOneDescriptor object at 0x112f1ce50>,
'assignmentfile_set': <django.db.models.fields.related_descriptors.ReverseManyToOneDescriptor object at 0x112eced00>,
'canceled_by': <django.db.models.fields.related_descriptors.ForwardManyToOneDescriptor object at 0x112f1c250>,
'canceled_by_id': <django.db.models.fields.related_descriptors.ForeignKeyDeferredAttribute object at 0x112f1c1f0>,
'class_type': <django.db.models.query_utils.DeferredAttribute object at 0x112f1c130>,
'classes': <django.db.models.fields.related_descriptors.ReverseManyToOneDescriptor object at 0x112fcd1f0>,
'classproblem_set': <django.db.models.fields.related_descriptors.ReverseManyToOneDescriptor object at 0x112f1cdf0>,
'course': <django.db.models.fields.related_descriptors.ForwardManyToOneDescriptor object at 0x112f13ca0>,
'course_id': <django.db.models.fields.related_descriptors.ForeignKeyDeferredAttribute object at 0x112f13c40>,
'date': <django.db.models.query_utils.DeferredAttribute object at 0x112f13ac0>,
'datetimestart': <django.db.models.query_utils.DeferredAttribute object at 0x112f1c4f0>,
'delay_from': <django.db.models.query_utils.DeferredAttribute object at 0x112f13ee0>,
'duration': <django.db.models.query_utils.DeferredAttribute object at 0x112f13b80>,
'eps': <django.db.models.fields.related_descriptors.ManyToManyDescriptor object at 0x112f1ca30>,
'esl_feedback': <django.db.models.fields.related_descriptors.ReverseOneToOneDescriptor object at 0x112f599a0>,
'exam_class': <django.db.models.fields.related_descriptors.ReverseManyToOneDescriptor object at 0x112fc6610>,
'extra_course': <django.db.models.fields.related_descriptors.ForwardManyToOneDescriptor object at 0x112f1c8e0>,
'extra_course_id': <django.db.models.fields.related_descriptors.ForeignKeyDeferredAttribute object at 0x112f1c880>,
'feedback': <django.db.models.fields.related_descriptors.ReverseOneToOneDescriptor object at 0x112f4eaf0>,
'get_class_type_display': functools.partialmethod(<function Model._get_FIELD_display at 0x1032f14c0>, , field=<django.db.models.fields.CharField: class_type>),
'homework_set': <django.db.models.fields.related_descriptors.ReverseManyToOneDescriptor object at 0x112f415b0>,
'id': <django.db.models.query_utils.DeferredAttribute object at 0x112f13a00>,
'ielts_feedback': <django.db.models.fields.related_descriptors.ReverseOneToOneDescriptor object at 0x112f5f790>,
'lesson': <django.db.models.fields.related_descriptors.ReverseManyToOneDescriptor object at 0x112fe7a00>,
'name': <django.db.models.query_utils.DeferredAttribute object at 0x112f13a60>,
'note': <django.db.models.query_utils.DeferredAttribute object at 0x112f1c340>,
'over': <django.db.models.query_utils.DeferredAttribute object at 0x112f1c0d0>,
'rate': <django.db.models.fields.related_descriptors.ReverseManyToOneDescriptor object at 0x112f482b0>,
'real_duration': <django.db.models.query_utils.DeferredAttribute object at 0x112f1c550>,
'screen_share': <django.db.models.query_utils.DeferredAttribute object at 0x112f1c5b0>,
'status': <django.db.models.fields.related_descriptors.ForwardManyToOneDescriptor object at 0x112f13fa0>,
'status_id': <django.db.models.fields.related_descriptors.ForeignKeyDeferredAttribute object at 0x112f13f40>,
'student_manager': <django.db.models.manager.ManagerDescriptor object at 0x112f1c9d0>,
'students': <django.db.models.fields.related_descriptors.ManyToManyDescriptor object at 0x112f1c670>,
'substitute_teacher': <django.db.models.fields.related_descriptors.ForwardManyToOneDescriptor object at 0x112f13df0>,
'substitute_teacher_id': <django.db.models.fields.related_descriptors.ForeignKeyDeferredAttribute object at 0x112f13d90>,
'teacher': <django.db.models.fields.related_descriptors.ForwardManyToOneDescriptor object at 0x112f1c400>,
'teacher_id': <django.db.models.fields.related_descriptors.ForeignKeyDeferredAttribute object at 0x112f1c3a0>,
'time': <django.db.models.query_utils.DeferredAttribute object at 0x112f13b20>,
'time_end': <django.db.models.query_utils.DeferredAttribute object at 0x112f1c610>,
'time_start': <django.db.models.query_utils.DeferredAttribute object at 0x112f1c7f0>,
'video': <django.db.models.fields.related_descriptors.ReverseManyToOneDescriptor object at 0x112f5ff40>})
如您所见,没有 objects
属性,我尝试使用其他带有 get_model() 的模型,它具有 objects
属性。为什么 CourseClass 是唯一缺少 objects
属性的课程?
我在自定义迁移过程中遇到过类似的问题。我认为原因之一是 get_model
返回的 class 有时不是完整的模型 class 您可以通过正确导入它获得。但是,get_model
调用对于确保在迁移时正确加载模型是必要的。这是因为在迁移时,模型应该代表上次迁移后的模型状态。如果管理器是稍后定义的,它还不会存在一个对我们有用的解决方法:
def update_student(apps, schema_editor):
_ = apps.get_model('backend', 'CourseClass')
# makes sure model is loaded
from path.to.backend.models import CourseClass
# gives you the proper class with all utils
# do your thang
TLDR:如果您想在迁移文件中进行查询,请在您的自定义管理器中添加 use_in_migrations = True
经过几个小时的搜索,我在关于模型管理器和迁移的文档中找到了这一部分
https://docs.djangoproject.com/en/3.2/topics/migrations/#model-managers
为了在迁移中使用自定义管理器,use_in_migrations = True
需要在管理器中设置,所以我将我的管理器更改为以下内容:
class StudentManager(models.Manager):
use_in_migrations = True
def student_query(self, student):
return super(StudentManager, self).get_queryset().filter(
Q(students=student) | Q(course__students=student
)).distinct('id')
class TeacherManager(models.Manager):
use_in_migrations = True
def teacher_query(self, teacher):
return super(TeacherManager, self).get_queryset().filter(
Q(teacher=teacher) | Q(course__teacher=teacher)|
Q(substitute_teacher=teacher)).distinct('id')
class MainCourseClassManager(models.Manager):
use_in_migrations = True
class CourseClass(models.Model):
class Meta:
db_table = 'classes'
verbose_name = _('Class')
verbose_name_plural = _('Classes')
objects = MainCourseClassManager()
student_manager = StudentManager()
teacher_manager = TeacherManager()
现在我的迁移可以使用 get_model()
也从文档中注意到
因为无法序列化任意 Python 代码,所以这些历史模型不会有您定义的任何自定义方法。但是,它们将具有相同的字段、关系、managers (limited to those with use_in_migrations = True)
和元选项(也是版本化的,因此它们可能与您当前的不同)。
解决方案应该更多 migrations.AlterModelManagers。
你必须在你的迁移中有这个:
migrations.AlterModelManagers(
name='entity',
managers=[
'objects', django.db.models.manager.Manager()),
],
),
这里解释一下:https://github.com/django-mptt/django-mptt/issues/489#issuecomment-243128053
我正在写一个迁移来更新数据,我像文档描述的那样使用 get_model() 来获取模型 class,如下所示:
from django.db import migrations
def update_student(apps, schema_editor):
# We can't import the model directly as it may be a newer
# version than this migration expects. We use the historical version.
CourseClass = apps.get_model('backend', 'CourseClass')
from pprint import pprint
pprint(vars(CourseClass))
for course_class in CourseClass.objects.all():
if course_class.course:
if course_class.course.student:
course_class.students.add(course_class.course.student)
Course = apps.get_model('backend', 'Course')
for course in Course.objects.all():
if course.student:
course.students.add(course.student)
class Migration(migrations.Migration):
dependencies = [
('backend', '0199_auto_20211027_1026'),
]
operations = [
migrations.RunPython(update_student, migrations.RunPython.noop)
]
这是我的模型和一些自定义管理器:
class CourseClass(models.Model):
class Meta:
db_table = 'classes'
verbose_name = _('Class')
verbose_name_plural = _('Classes')
student_manager = StudentManager()
teacher_manager = TeacherManager()
objects = models.Manager()
# other fields
当 运行 我的迁移时,我收到以下错误:
File "/Users/admin/Library/Caches/pypoetry/virtualenvs/base.django-AnqsdXoZ-py3.8/lib/python3.8/site-packages/django/db/migrations/operations/special.py", line 190, in database_forwards
self.code(from_state.apps, schema_editor)
File "/Users/admin/Documents/git/icts/vietphil.hoola/backend/migrations/0200_update_student.py", line 13, in update_student
for course_class in CourseClass.objects.all():
AttributeError: type object 'CourseClass' has no attribute 'objects
使用 pprint return 打印 CourseClass 的属性如下:
mappingproxy({'DoesNotExist': <class '__fake__.CourseClass.DoesNotExist'>,
'MultipleObjectsReturned': <class '__fake__.CourseClass.MultipleObjectsReturned'>,
'__doc__': 'CourseClass(id, name, date, time, duration, course, '
'substitute_teacher, delay_from, status, over, '
'class_type, canceled_by, note, teacher, '
'datetimestart, real_duration, screen_share, '
'time_end, time_start, extra_course)',
'__module__': '__fake__',
'_meta': <Options for CourseClass>,
'assignment_class': <django.db.models.fields.related_descriptors.ReverseOneToOneDescriptor object at 0x112f1ce50>,
'assignmentfile_set': <django.db.models.fields.related_descriptors.ReverseManyToOneDescriptor object at 0x112eced00>,
'canceled_by': <django.db.models.fields.related_descriptors.ForwardManyToOneDescriptor object at 0x112f1c250>,
'canceled_by_id': <django.db.models.fields.related_descriptors.ForeignKeyDeferredAttribute object at 0x112f1c1f0>,
'class_type': <django.db.models.query_utils.DeferredAttribute object at 0x112f1c130>,
'classes': <django.db.models.fields.related_descriptors.ReverseManyToOneDescriptor object at 0x112fcd1f0>,
'classproblem_set': <django.db.models.fields.related_descriptors.ReverseManyToOneDescriptor object at 0x112f1cdf0>,
'course': <django.db.models.fields.related_descriptors.ForwardManyToOneDescriptor object at 0x112f13ca0>,
'course_id': <django.db.models.fields.related_descriptors.ForeignKeyDeferredAttribute object at 0x112f13c40>,
'date': <django.db.models.query_utils.DeferredAttribute object at 0x112f13ac0>,
'datetimestart': <django.db.models.query_utils.DeferredAttribute object at 0x112f1c4f0>,
'delay_from': <django.db.models.query_utils.DeferredAttribute object at 0x112f13ee0>,
'duration': <django.db.models.query_utils.DeferredAttribute object at 0x112f13b80>,
'eps': <django.db.models.fields.related_descriptors.ManyToManyDescriptor object at 0x112f1ca30>,
'esl_feedback': <django.db.models.fields.related_descriptors.ReverseOneToOneDescriptor object at 0x112f599a0>,
'exam_class': <django.db.models.fields.related_descriptors.ReverseManyToOneDescriptor object at 0x112fc6610>,
'extra_course': <django.db.models.fields.related_descriptors.ForwardManyToOneDescriptor object at 0x112f1c8e0>,
'extra_course_id': <django.db.models.fields.related_descriptors.ForeignKeyDeferredAttribute object at 0x112f1c880>,
'feedback': <django.db.models.fields.related_descriptors.ReverseOneToOneDescriptor object at 0x112f4eaf0>,
'get_class_type_display': functools.partialmethod(<function Model._get_FIELD_display at 0x1032f14c0>, , field=<django.db.models.fields.CharField: class_type>),
'homework_set': <django.db.models.fields.related_descriptors.ReverseManyToOneDescriptor object at 0x112f415b0>,
'id': <django.db.models.query_utils.DeferredAttribute object at 0x112f13a00>,
'ielts_feedback': <django.db.models.fields.related_descriptors.ReverseOneToOneDescriptor object at 0x112f5f790>,
'lesson': <django.db.models.fields.related_descriptors.ReverseManyToOneDescriptor object at 0x112fe7a00>,
'name': <django.db.models.query_utils.DeferredAttribute object at 0x112f13a60>,
'note': <django.db.models.query_utils.DeferredAttribute object at 0x112f1c340>,
'over': <django.db.models.query_utils.DeferredAttribute object at 0x112f1c0d0>,
'rate': <django.db.models.fields.related_descriptors.ReverseManyToOneDescriptor object at 0x112f482b0>,
'real_duration': <django.db.models.query_utils.DeferredAttribute object at 0x112f1c550>,
'screen_share': <django.db.models.query_utils.DeferredAttribute object at 0x112f1c5b0>,
'status': <django.db.models.fields.related_descriptors.ForwardManyToOneDescriptor object at 0x112f13fa0>,
'status_id': <django.db.models.fields.related_descriptors.ForeignKeyDeferredAttribute object at 0x112f13f40>,
'student_manager': <django.db.models.manager.ManagerDescriptor object at 0x112f1c9d0>,
'students': <django.db.models.fields.related_descriptors.ManyToManyDescriptor object at 0x112f1c670>,
'substitute_teacher': <django.db.models.fields.related_descriptors.ForwardManyToOneDescriptor object at 0x112f13df0>,
'substitute_teacher_id': <django.db.models.fields.related_descriptors.ForeignKeyDeferredAttribute object at 0x112f13d90>,
'teacher': <django.db.models.fields.related_descriptors.ForwardManyToOneDescriptor object at 0x112f1c400>,
'teacher_id': <django.db.models.fields.related_descriptors.ForeignKeyDeferredAttribute object at 0x112f1c3a0>,
'time': <django.db.models.query_utils.DeferredAttribute object at 0x112f13b20>,
'time_end': <django.db.models.query_utils.DeferredAttribute object at 0x112f1c610>,
'time_start': <django.db.models.query_utils.DeferredAttribute object at 0x112f1c7f0>,
'video': <django.db.models.fields.related_descriptors.ReverseManyToOneDescriptor object at 0x112f5ff40>})
如您所见,没有 objects
属性,我尝试使用其他带有 get_model() 的模型,它具有 objects
属性。为什么 CourseClass 是唯一缺少 objects
属性的课程?
我在自定义迁移过程中遇到过类似的问题。我认为原因之一是 get_model
返回的 class 有时不是完整的模型 class 您可以通过正确导入它获得。但是,get_model
调用对于确保在迁移时正确加载模型是必要的。这是因为在迁移时,模型应该代表上次迁移后的模型状态。如果管理器是稍后定义的,它还不会存在一个对我们有用的解决方法:
def update_student(apps, schema_editor):
_ = apps.get_model('backend', 'CourseClass')
# makes sure model is loaded
from path.to.backend.models import CourseClass
# gives you the proper class with all utils
# do your thang
TLDR:如果您想在迁移文件中进行查询,请在您的自定义管理器中添加 use_in_migrations = True
经过几个小时的搜索,我在关于模型管理器和迁移的文档中找到了这一部分
https://docs.djangoproject.com/en/3.2/topics/migrations/#model-managers
为了在迁移中使用自定义管理器,use_in_migrations = True
需要在管理器中设置,所以我将我的管理器更改为以下内容:
class StudentManager(models.Manager):
use_in_migrations = True
def student_query(self, student):
return super(StudentManager, self).get_queryset().filter(
Q(students=student) | Q(course__students=student
)).distinct('id')
class TeacherManager(models.Manager):
use_in_migrations = True
def teacher_query(self, teacher):
return super(TeacherManager, self).get_queryset().filter(
Q(teacher=teacher) | Q(course__teacher=teacher)|
Q(substitute_teacher=teacher)).distinct('id')
class MainCourseClassManager(models.Manager):
use_in_migrations = True
class CourseClass(models.Model):
class Meta:
db_table = 'classes'
verbose_name = _('Class')
verbose_name_plural = _('Classes')
objects = MainCourseClassManager()
student_manager = StudentManager()
teacher_manager = TeacherManager()
现在我的迁移可以使用 get_model()
也从文档中注意到
因为无法序列化任意 Python 代码,所以这些历史模型不会有您定义的任何自定义方法。但是,它们将具有相同的字段、关系、managers (limited to those with use_in_migrations = True)
和元选项(也是版本化的,因此它们可能与您当前的不同)。
解决方案应该更多 migrations.AlterModelManagers。
你必须在你的迁移中有这个:
migrations.AlterModelManagers(
name='entity',
managers=[
'objects', django.db.models.manager.Manager()),
],
),
这里解释一下:https://github.com/django-mptt/django-mptt/issues/489#issuecomment-243128053