您的位置:

django有ValueError("Join generated an empty ON clause. %s did not yield either ""joining columns or extra restrictions." % declared_field.__class__)报错是怎么回事

  发布时间:2023-03-09 07:14:14
报错的原因这个错误通常是由于在使用 Django ORM 的 join() 方法时传入的关联字段没有产生任何有用的 ON 条件。例如,如果你使用以下代码就会出现 ValueError 异常,因为 title 字段不是关联字段。如何解决要解决 ValueError 异常,你需要确保传入 join() 方法的字段是关联字段。

报错的原因

ValueError("Join generated an empty ON clause. %s did not yield either joining columns or extra restrictions." % declared_field.__class__) 这个错误通常是由于在使用 Django ORM 的 join() 方法时传入的关联字段没有产生任何有用的 ON 条件。

join() 方法是用来在查询中加入关联字段的。例如,假设你有以下两个模型:


class Blog(models.Model):
    name = models.CharField(max_length=100)

class Entry(models.Model):
    blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
    title = models.CharField(max_length=200)
    body = models.TextField()

在这个例子中,Blog 和 Entry 模型之间有一个外键关系(blog 字段是 Entry 模型的外键)。如果你想在查询中加入 blog 字段,你可以使用以下代码:


entries = Entry.objects.join(Blog).all()

在上面的代码中,我们使用 join(Blog) 方法来加入 blog 字段。

如果传入 join() 方法的字段不是关联字段(例如 ForeignKey、OneToOneField、ManyToManyField 等),就会出现 ValueError 异常,错误信息中会给出提示。

例如,如果你使用以下代码:


entries = Entry.objects.join(title).all()

就会出现 ValueError 异常,因为 title 字段不是关联字段。

方法。

例如,如果你想加入 Entry 模型的 blog 字段,你可以使用以下代码:


entries = Entry.objects.join(Blog).all()

如果你想加入 Blog 模型的 owner 字段(假设 owner 字段是一个 ForeignKey 字段),你可以使用以下代码:


blogs = Blog.objects.join(Owner).all()

如果你想加入 Blog 模型的 tags 字段(假设 tags 字段是一个 ManyToManyField 字段),你可以使用以下代码:


blogs = Blog.objects.join(Tag).all()

希望这些例子能帮助你解决 ValueError 异常。

如何解决

要解决 ValueError 异常,你需要确保传入 join() 方法的字段是关联字段。你可以使用 ForeignKey、OneToOneField、ManyToManyField 等字段作为参数传入 join() 方法。

例如,如果你想加入 Entry 模型的 blog 字段,你可以使用以下代码:


entries = Entry.objects.join(Blog).all()

如果你想加入 Blog 模型的 owner 字段(假设 owner 字段是一个 ForeignKey 字段),你可以使用以下代码:


blogs = Blog.objects.join(Owner).all()

如果你想加入 Blog 模型的 tags 字段(假设 tags 字段是一个 ManyToManyField 字段),你可以使用以下代码:


blogs = Blog.objects.join(Tag).all()

请注意,在使用 Django ORM 的时候,错误信息通常会提供很多有用的信息,帮助你分析问题并找到解决方案。

例如,在本例中,ValueError 异常信息提示我们 join() 方法产生了一个空的 ON 条件,并指出了原因:declared_field.__class__ 不是关联字段。这个信息提示我们应该确保传入 join() 方法的字段是关联字段。

案。

还有一些其他的常见错误和解决方法:

- AttributeError("Manager isn't available; Entry has been deleted.")

这个错误通常是由于在删除 Entry 对象之后仍然使用了这个对象的 Manager 属性。例如:


entry = Entry.objects.get(id=1)
entry.delete()
entry.objects.all()  # AttributeError

要解决这个错误,你需要确保在删除对象之后不要再使用这个对象的 Manager 属性。例如:


Entry.objects.get(id=1).delete()

- FieldError("Cannot resolve keyword '...' into field. Choices are: ...")

这个错误通常是由于在使用 Django ORM 的 filter() 方法时传入的字段名称不正确。例如:


Entry.objects.filter(title="My Entry")  # FieldError

- IntegrityError("...")

这个错误通常是由于尝试插入或更新数据库记录时,违反了数据库的完整性约束。例如,你可能会尝试插入一条新的数据记录,但是数据库中已经存在了一条具有相同主键的记录,导致了主键冲突。

要解决这个错误,你需要检查你的代码,确保不会违反数据库的完整性约束。例如,如果你正在尝试插入一条新的数据记录,你可以使用 get_or_create() 方法来避免主键冲突:


obj, created = MyModel.objects.get_or_create(pk=1)

这个方法会尝试获取主键为 1 的记录,如果记录存在,则返回记录;如果记录不存在,则会新建一条记录,并返回新建的记录。

使用例子

是的,下面是一些例子:

如果你想查询邮箱地址是 "john@example.com" 的用户,你可以使用以下代码:


from django.contrib.auth import get_user_model

User = get_user_model()

user = User.objects.get(email="john@example.com")

如果你想查询年龄大于 30 岁的用户,你可以使用以下代码:


from django.utils import timezone

today = timezone.now().date()
users = User.objects.filter(date_of_birth__lte=today - timezone.timedelta(days=365*30))

如果你想查询年龄在 20 到 30 岁之间的用户,你可以使用以下代码:


users = User.objects.filter(date_of_birth__lte=today - timezone.timedelta(days=365*20),
                            date_of_birth__gte=today - timezone.timedelta(days=365*30))

希望这些例子能帮助你开始使用 Django ORM。