在SQLAlchemy中,hybrid attribute是应用于ORM映射类的property或方法,
class Interval(Base):
__tablename__ = 'interval'
id = Column(Integer, primary_key=True)
start = Column(Integer, nullable=False)
end = Column(Integer, nullable=False)
def __init__(self, start, end):
self.start = start
self.end = end
@hybrid_property
def length(self):
return self.end - self.start
@hybrid_method
def contains(self,point):
return (self.start <= point) & (point < self.end)
@hybrid_method
def intersects(self, other):
return self.contains(other.start) | self.contains(other.end)
这允许在类和实例级别执行不同的行为,从而使使用相同代码评估SQL语句变得更加简单,
>>> i1 = Interval(5, 10)
>>> i1.length
5
>>> print Session().query(Interval).filter(Interval.length > 10)
SELECT interval.id AS interval_id, interval.start AS interval_start,
interval."end" AS interval_end
FROM interval
WHERE interval."end" - interval.start > :param_1
现在在Django,如果我在模型上有属性,
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
def _get_full_name(self):
"Returns the person's full name."
return '%s %s' % (self.first_name, self.last_name)
full_name = property(_get_full_name)
我可以 执行以下操作understanding,
Person.objects.filter(full_name="John Cadengo")
Django中是否有SQLAlchemy的混合属性?如果没有,是否有一个共同的解决方法?
答案 0 :(得分:2)
你是对的,你不能应用基于python属性的django queryset过滤器,因为过滤器在数据库级别上运行。似乎在Django中没有SQLAlchemy的混合属性。
答案 1 :(得分:1)
一种可能的快速解决方法是实现一些描述符,这将通过注释应用表达式。 像这样:
from django.db import models
from django.db.models import functions
class hybrid_property:
def __init__(self, func):
self.func = func
self.name = func.__name__
self.exp = None
def __get__(self, instance, owner):
if instance is None:
return self
return self.func(instance)
def __set__(self, instance, value):
pass
def expression(self, exp):
self.exp = exp
return self
class HybridManager(models.Manager):
def get_queryset(self):
qs = super().get_queryset()
for name, value in vars(qs.model).items():
if isinstance(value, hybrid_property) and value.exp is not None:
qs = qs.annotate(**{name: value.exp(qs.model)})
return qs
class TestAttribute(models.Model):
val1 = models.CharField(max_length=256)
val2 = models.CharField(max_length=256)
objects = HybridManager()
@hybrid_property
def vals(self):
return f"{self.val1} {self.val2}"
@vals.expression
def vals(cls):
return functions.Concat(models.F("val1"), models.Value(" "), models.F("val2"))
class HybridTests(TestCase):
def setUp(self) -> None:
self.test_attr = TestAttribute.objects.create(val1="val1", val2="val2")
def test_access(self):
self.assertTrue(TestAttribute.objects.exists())
self.assertEqual(self.test_attr.vals, f"{self.test_attr.val1} {self.test_attr.val2}")
self.assertTrue(TestAttribute.objects.filter(vals=f"{self.test_attr.val1} {self.test_attr.val2}").exists())
self.assertTrue(TestAttribute.objects.filter(vals__iexact=f"{self.test_attr.val1} {self.test_attr.val2}").exists())