#python #sqlalchemy #python-elixir
#python #sqlalchemy #python-elixir
Вопрос:
У меня есть класс:
from sys import stderr
from elixir import *
from types import *
class User(Entity):
using_options(tablename="users")
first_name = Field(String(50))
middle_name = Field(String(50))
last_name = Field(String(50))
def __get_name__ (self):
first_name = self.first_name if self.first_name is not None else ""
middle_name = self.middle_name if self.middle_name is not None else ""
last_name = self.last_name if self.last_name is not None else ""
return " ".join((first_name, middle_name, last_name)).strip()
def __set_name__ (self,string):
first_name = ""
middle_name = ""
last_name = ""
split_string = string.split(' ')
if len(split_string) == 1:
first_name = string
elif len(split_string) == 2:
first_name, last_name = split_string
elif len(split_string) == 3:
first_name, middle_name, last_name = split_string
else: #len(split_string) > 3:
first_name = split_string[0]
last_name = split_string[-1]
middle_name = " ".join(split_string[1:-2])
self.first_name = first_name
self.middle_name = middle_name
self.last_name = last_name
name = property(__get_name__,__set_name__)
Я хотел бы выполнить запрос следующим образом:
def get_user(user):
found = None
if type(user) in [IntType,StringType]:
if type(user) is StringType:
where = or_(User.first_name==user,
User.middle_name==user,
User.last_name==user,
User.name==user)
qry = User.query.filter(where)
elif type(user) is IntType:
where = or_(User.id==user,
User.employee_id==user)
qry = User.query.filter(where)
try:
found = qry.one()
except NoResultFound:
print >> stderr, "Couldn't find '%s'" % user
elif type(user) == User:
found=user
return found
Однако результирующий SQL-запрос выглядит примерно следующим образом:
SELECT users.first_name AS users_first_name,
users.middle_name AS users_middle_name,
users.last_name AS users_last_name
FROM users
WHERE users.first_name = 'Joseph'
OR users.middle_name = 'M'
OR users.last_name = 'Schmoe'
OR false
Обратите внимание на «false» вместо User.name поле.
Я получаю эту ошибку:
sqlalchemy.exc.OperationalError: (OperationalError) no such column: false
Я думаю, что я бы хотел, чтобы SQL-запрос выглядел следующим образом:
SELECT users.name
FROM users
WHERE users.name = 'Joseph M Schmoe'
Редактировать: желаемый / второй SQL-запрос был неверным для того, что я действительно хотел: какой-то пассивный способ создания поля ‘name’ в базе данных, которое соответствует объединению ‘first_name’, ‘middle_name’, ‘last_name’.
Редактирование 2: я считаю, что следующее поможет мне почти достичь цели. Тем не менее, я все еще борюсь с правильным выражением.
Edit3: похоже, это работает для того, что мне нужно. Поэтому я включаю его в качестве ответа.
Комментарии:
1. User.name это похоже на @property def name(self): return foo # попробуйте выполнить запрос без этого оператора User.name==user, потому что вы запрашиваете тип свойства
2. @rob.alarcon: 😉 Запрос выполняется просто отлично, без лишней строки. Но когда я выполняю запрос, я специально хочу использовать ORM для создания полезного свойства в запросе.
3.
__set_name__
теперь это зарезервированное специальное имя метода в Python 3.6
Ответ №1:
Вы определяете свойство, и оно будет доступно после назначения объекта.
Примечание: я изменяю ваш код для своего удобства
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, DateTime, String
from datetime import datetime
Base = declarative_base()
class User(Base):
first_name = Column('first_name', String)
middle_name = Column('middle_name', String)
last_name = Column('last_name', String)
def __get_name__ (self):
first_name = self.first_name if self.first_name is not None else ""
middle_name = self.middle_name if self.middle_name is not None else ""
last_name = self.last_name if self.last_name is not None else ""
return " ".join((first_name, middle_name, last_name)).strip()
def __set_name__ (self,string):
first_name = ""
middle_name = ""
last_name = ""
split_string = string.split(' ')
if len(split_string) == 1:
first_name = string
elif len(split_string) == 2:
first_name, last_name = split_string
elif len(split_string) == 3:
first_name, middle_name, last_name = split_string
else: #len(split_string) > 3:
first_name = split_string[0]
last_name = split_string[-1]
middle_name = " ".join(split_string[1:-2])
self.first_name = first_name
self.middle_name = middle_name
self.last_name = last_name
name = property(__get_name__,__set_name__)
То first_name, middle_name and last_name
же самое относится и к атрибутам класса. Когда вы определяете свойство, ему нужен экземпляр этого объекта.
In [13]: User.first_name
Out[13]: Column('first_name', String(), )
In [14]: User.name
Out[14]: <property object at 0x26fef70>
В приведенном выше примере вы можете увидеть разницу. Пока вы не установите это свойство или любые поля этого свойства, оно всегда будет пустым.
Вы должны предоставить
In [16]: u1 = User()
In [17]: u1.name = "first middle last"
In [18]: u1.name
Out[18]: 'first middle last'
In [19]: u1.first_name
Out[19]: 'first'
После этого вы можете использовать свойство.
Это поможет вам понять вашу проблему. Ваше свойство связано с экземпляром, к которому вы не можете получить доступ по классу.
Комментарии:
1. Я полагаю, что вы, возможно, запутали мою проблему, когда вы перешли с Elixir на Sqlalchemy. Я хочу использовать name, как если бы это был атрибут класса. Здесь есть пример SQA, но я хочу, чтобы это было сделано в Elixir. Я считаю, что соответствующее использование имеет какое-то отношение к ColumnProperty здесь . Однако документация не очень хорошо поддается. У Google есть что-то здесь , но оно не имеет дело со строками.
2.
__set_name__
теперь это зарезервированное имя метода в Python 3.6
Ответ №2:
from sqlalchemy.ext.hybrid import hybrid_property
@hybrid_property
def name (self):
first_name = self.first_name if self.first_name is not None else ""
middle_name = self.middle_name if self.middle_name is not None else ""
last_name = self.last_name if self.last_name is not None else ""
return " ".join((first_name, middle_name, last_name)).strip()
@name.setter
def name (self,string):
first_name = ""
middle_name = ""
last_name = ""
split_string = string.split(' ')
if len(split_string) == 1:
first_name = string
elif len(split_string) == 2:
first_name, last_name = split_string
elif len(split_string) == 3:
first_name, middle_name, last_name = split_string
else: #len(split_string) > 3:
first_name = split_string[0]
last_name = split_string[-1]
middle_name = " ".join(split_string[1:-2])
self.first_name = first_name
self.middle_name = middle_name
self.last_name = last_name
Часть выражения находится здесь:
@name.expression
def name (cls):
f = cls.first_name
m = cls.middle_name
l = cls.last_name
return f ' ' m ' ' l