I want to filter some database objects by a concatenated string.
The normal SQL query would be:
SELECT concat(firstName, ' ', name) FROM person WHERE CONCAT(firstName, ' ', name) LIKE "a%";
In the model, I have created a manager called PersonObjects:
class PersonObjects(Manager):
attrs = {
'fullName': "CONCAT(firstName, ' ', name)"
}
def get_query_set(self):
return super(PersonObjects, self).get_query_set().extra(
select=self.attrs)
I also configured this in my model:
objects = managers.PersonObjects()
Now accessing fullName works for single objects:
>>> p = models.Person.objects.get(pk=4)
>>> p.fullName
u'Fred Borminski'
But it does not work in a filter:
>>> p = models.Person.objects.filter(fullName__startswith='Alexei')
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/usr/lib/python2.7/site-packages/django/db/models/manager.py", line 141, in filter
return self.get_query_set().filter(*args, **kwargs)
File "/usr/lib/python2.7/site-packages/django/db/models/query.py", line 550, in filter
return self._filter_or_exclude(False, *args, **kwargs)
File "/usr/lib/python2.7/site-packages/django/db/models/query.py", line 568, in _filter_or_exclude
clone.query.add_q(Q(*args, **kwargs))
File "/usr/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1128, in add_q
can_reuse=used_aliases)
File "/usr/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1026, in add_filter
negate=negate, process_extras=process_extras)
File "/usr/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1191, in setup_joins
"Choices are: %s" % (name, ", ".join(names)))
FieldError: Cannot resolve keyword 'fullName' into field. Choices are: firstName, gender, name, (...)
Is this a bug or a feature? How can I fix this?
Thanks.
It's not a bug. filter() only inspects model definitions, so it doesn't recognize fullName as a declared field (because it's not - it's an extra argument in a query).
You can add the fullName to WHERE using extra():
Person.objects.extra(where=["fullName LIKE %s"], params=["Alexei%"])
I solved this by implementing a custom Aggregate function.
In this case I needed to concatenate individual fields into a street address to be able to filter/search for matches.
The following aggregate function allows to specify a field and one or more others to perform a SQL CONCAT_WS.
Edit 3 Aug 2015:
A better implementation with details gleaned from https://stackoverflow.com/a/19529861/3230522. The previous implementation would fail if the queryset was used in a subquery. The table names are now correct, although I note that this just works for concatenation of columns from the same table.
from django.db.models import Aggregate
from django.db.models.sql.aggregates import Aggregate as SQLAggregate
class SqlAggregate(SQLAggregate):
sql_function = 'CONCAT_WS'
sql_template = u'%(function)s(" ", %(field)s, %(columns_to_concatenate)s)'
def as_sql(self, qn, connection):
self.extra['columns_to_concatenate'] = ', '.join(
['.'.join([qn(self.col[0]), qn(c.strip())]) for c in self.extra['with_columns'].split(',')])
return super(SqlAggregate, self).as_sql(qn, connection)
class Concatenate(Aggregate):
sql = SqlAggregate
def __init__(self, expression, **extra):
super(Concatenate, self).__init__(
expression,
**extra)
def add_to_query(self, query, alias, col, source, is_summary):
aggregate = self.sql(col,
source=source,
is_summary=is_summary,
**self.extra)
query.aggregates[alias] = aggregate
The proposed solution worked great with postgresql and JSONB fields in the code below. Only records that have the 'partner' key under the 'key' jsonb field are returned:
query_partner = "select key->>'partner' from accounting_subaccount " \
"where accounting_subaccount.id = subaccount_id and key ? 'partner'"
qs = queryset.extra(select={'partner': query_partner}, where=["key ? 'partner'"])
Related
I'm trying to be able to dynamically sort a query by a given column name and have nulls be placed at the end of the list. It works fine when using desc ordering, but raises a ProgrammingError when trying to use nulls_last with asc order. It appears this error is being raised as the result of an InvalidArgument error (see Traces below).
Dependencies
sqlalchemy = "~1.4.37"
sqlalchemy-spanner = "~1.2.0"
We're using Google Cloud Spanner for our database.
Original Query
Generating Method
#classmethod
def get_my_models(cls, sort_by: str, order_by: str) -> List["MyModel"]:
with read_session_scope(get_engine()) as session:
sort_attr = getattr(MyModel, sort_by)
query = (
session.query(MyModel)
.filter(func.coalesce(MyModel.is_deleted, False).is_(False))
.order_by(nulls_last(getattr(sort_attr, order_by)()))
)
return [MyModel.from_orm(model) for model in query.all()]
Translated Query
When called with sort_by="my_column" and order_by="desc"
SELECT ... FROM my_model WHERE coalesce(my_model.is_deleted, false) IS false ORDER BY
my_model.my_column DESC NULLS LAST
The above works fine. So as long as I want to order by descending, I'm good. Unfortunately, that's not the requirement.
When called with sort_by="my_column" and order_by="asc"
SELECT ... FROM my_model WHERE coalesce(my_model.is_deleted, false) IS false ORDER BY
my_model.my_column ASC NULLS LAST
it looks great, but it raises:
sqlalchemy.exc.ProgrammingError: (google.cloud.spanner_dbapi.exceptions.ProgrammingError)
The error is raised in the last line of the query method during query.all()
Traces
File "/opt/pysetup/.venv/lib/python3.8/site-packages/sqlalchemy/orm/query.py", line 2768, in all
return self._iter().all()
File "/opt/pysetup/.venv/lib/python3.8/site-packages/sqlalchemy/orm/query.py", line 2903, in _iter
result = self.session.execute(
File "/opt/pysetup/.venv/lib/python3.8/site-packages/sqlalchemy/orm/session.py", line 1712, in execute
result = conn._execute_20(statement, params or {}, execution_options)
File "/opt/pysetup/.venv/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1631, in _execute_20
return meth(self, args_10style, kwargs_10style, execution_options)
File "/opt/pysetup/.venv/lib/python3.8/site-packages/sqlalchemy/sql/elements.py", line 332, in _execute_on_connection
return connection._execute_clauseelement(
File "/opt/pysetup/.venv/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1498, in _execute_clauseelement
ret = self._execute_context(
File "/opt/pysetup/.venv/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1862, in _execute_context
self._handle_dbapi_exception(
File "/opt/pysetup/.venv/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 2043, in _handle_dbapi_exception
util.raise_(
File "/opt/pysetup/.venv/lib/python3.8/site-packages/sqlalchemy/util/compat.py", line 208, in raise_
raise exception
File "/opt/pysetup/.venv/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1819, in _execute_context
self.dialect.do_execute(
File "/opt/pysetup/.venv/lib/python3.8/site-packages/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py", line 1006, in do_execute
cursor.execute(statement, parameters)
File "/opt/pysetup/.venv/lib/python3.8/site-packages/google/cloud/spanner_dbapi/cursor.py", line 70, in wrapper
return function(cursor, *args, **kwargs)
File "/opt/pysetup/.venv/lib/python3.8/site-packages/google/cloud/spanner_dbapi/cursor.py", line 286, in execute
raise ProgrammingError(getattr(e, "details", e))
sqlalchemy.exc.ProgrammingError: (google.cloud.spanner_dbapi.exceptions.ProgrammingError) []
self = <google.cloud.spanner_dbapi.cursor.Cursor object at 0xffffacfca220>
sql = 'SELECT ... coalesce(my_model.is_deleted, #a0) IS false ORDER BY my_model.my_column ASC NULLS LAST'
args = {'a0': False}
#check_not_closed
def execute(self, sql, args=None):
"""Prepares and executes a Spanner database operation.
:type sql: str
:param sql: A SQL query statement.
:type args: list
:param args: Additional parameters to supplement the SQL query.
"""
self._result_set = None
try:
if self.connection.read_only:
self._handle_DQL(sql, args or None)
return
class_ = parse_utils.classify_stmt(sql)
if class_ == parse_utils.STMT_DDL:
self._batch_DDLs(sql)
if self.connection.autocommit:
self.connection.run_prior_DDL_statements()
return
# For every other operation, we've got to ensure that
# any prior DDL statements were run.
# self._run_prior_DDL_statements()
self.connection.run_prior_DDL_statements()
if class_ == parse_utils.STMT_UPDATING:
sql = parse_utils.ensure_where_clause(sql)
if class_ != parse_utils.STMT_INSERT:
sql, args = sql_pyformat_args_to_spanner(sql, args or None)
if not self.connection.autocommit:
statement = Statement(
sql,
args,
get_param_types(args or None)
if class_ != parse_utils.STMT_INSERT
else {},
ResultsChecksum(),
class_ == parse_utils.STMT_INSERT,
)
(
self._result_set,
self._checksum,
) = self.connection.run_statement(statement)
while True:
try:
self._itr = PeekIterator(self._result_set)
break
except Aborted:
self.connection.retry_transaction()
return
if class_ == parse_utils.STMT_NON_UPDATING:
self._handle_DQL(sql, args or None)
elif class_ == parse_utils.STMT_INSERT:
_helpers.handle_insert(self.connection, sql, args or None)
else:
self.connection.database.run_in_transaction(
self._do_execute_update, sql, args or None
)
except (AlreadyExists, FailedPrecondition, OutOfRange) as e:
raise IntegrityError(getattr(e, "details", e))
except InvalidArgument as e:
> raise ProgrammingError(getattr(e, "details", e))
E sqlalchemy.exc.ProgrammingError: (google.cloud.spanner_dbapi.exceptions.ProgrammingError) []
Google Cloud Spanner databases using the standard GoogleSQL dialect always sort NULL first when the sort order is ascending, and NULL last when the sort order is descending. The SQL dialect allows you to specify ASC NULLS FIRST and DESC NULLS LAST, as those correspond with the default, but not to actually change the sort order.
A workaround for this would be to use a COALESCE(my_column, <large-value>) expression in your ORDER BY clause. The feasibility of this workaround depends a little on the data type of the column that you are sorting. If it is for example an INT64 column, you could just use the max value for INT64. Be aware though that such a workaround can make your query less efficient, as the ORDER BY clause will not be able to use any index that you might have defined on the column.
First of all please sorry for my English. ))
So I have a problem with Django import-export library when I try to import data from csv/xls/xlsx files to the Django application DB.
How it looks like.
Here is my models.py:
class Department(models.Model):
department_name = models.CharField(max_length = 50, default = '')
def __str__(self):
return f'{self.department_name}'
class ITHardware(models.Model):
it_hardware_model = models.CharField(max_length = 100)
it_hardware_serial_number = models.CharField(max_length = 100,
blank = True, default = '')
it_hardware_department = models.ForeignKey(Department,
related_name = 'department', on_delete = models.SET_NULL, default = '',
null = True, blank = True, db_constraint=False)
admin.py:
#admin.register(Department)
class DepartmentAdmin(admin.ModelAdmin):
list_display = ('department_name', )
actions = [duplicate_object]
#admin.register(ITHardwareManufacturer)
class ITHardwareManufacturerAdmin(admin.ModelAdmin):
list_display = ('manufacturer', )
actions = [duplicate_object]
class ITHardwareImportExportAdmin(ImportExportModelAdmin):
resource_class = ITHardwareResource
list_display = ['id', 'it_hardware_manufacturer',
'it_hardware_model', 'it_hardware_serial_number',
'it_hardware_department']
actions = [duplicate_object]
resource.py:
class ITHardwareResource(resources.ModelResource):
it_hardware_department = fields.Field(
column_name = 'it_hardware_department',
attribute = 'ITHardware.it_hardware_department',
widget = widgets.ForeignKeyWidget(Department, field = 'department_name'))
class Meta():
model = ITHardware
fields = (
'id',
'it_hardware_model',
'it_hardware_serial_number',
'it_hardware_department',
)
export_order = (
'id',
'it_hardware_model',
'it_hardware_serial_number',
'it_hardware_department',
)
import file:
If I try to import data from file, I get such error:
String number: 1 - ITHardwareManufacturer matching query does not exist.
None, Canon, BX500CI, 5B1837T00976, Office_1, IT_1
And so on.
OK. When I fill Department table manually via adminpanel (pointed there IT_1, 2, 3 and 4 departments) I get this preview:
and then I get this error:
Please explain me what am I doing wrong and how to fix it.
Update
If I understood the concept correctly, then "column_name" is the name of the column from which/to which data is imported/exported, and "attribute" is the name of the database field for the same operations.
The export works fine for me.
However, for import, as I understand it, I incorrectly describe the mechanism for ForeignKey. That is, I'm trying to tell Django that when importing data from the "it_hardware_department" column of the file, this data should be written to the "it_hardware_department" field of the Department model using ForeignKeyWidget.
Perhaps some intermediate action is required to determine the mechanism for writing data to the Department model, where to specify something like "Department__it_hardware_department"?
Update: traceback
Traceback (most recent call last):
File "C:\users\iv\mip\mip_env\lib\site-packages\django\db\backends\base\base.py", line 242, in _commit
return self.connection.commit()
The above exception (FOREIGN KEY constraint failed) was the direct cause of the following exception:
File "C:\users\iv\mip\mip_env\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
response = get_response(request)
File "C:\users\iv\mip\mip_env\lib\site-packages\django\core\handlers\base.py", line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\users\iv\mip\mip_env\lib\site-packages\django\utils\decorators.py", line 130, in _wrapped_view
response = view_func(request, *args, **kwargs)
File "C:\users\iv\mip\mip_env\lib\site-packages\django\views\decorators\cache.py", line 44, in _wrapped_view_func
response = view_func(request, *args, **kwargs)
File "C:\users\iv\mip\mip_env\lib\site-packages\django\contrib\admin\sites.py", line 232, in inner
return view(request, *args, **kwargs)
File "C:\users\iv\mip\mip_env\lib\site-packages\django\utils\decorators.py", line 43, in _wrapper
return bound_method(*args, **kwargs)
File "C:\users\iv\mip\mip_env\lib\site-packages\django\views\decorators\http.py", line 40, in inner
return func(request, *args, **kwargs)
File "C:\users\iv\mip\mip_env\lib\site-packages\import_export\admin.py", line 113, in process_import
result = self.process_dataset(dataset, confirm_form, request, *args, **kwargs)
File "C:\users\iv\mip\mip_env\lib\site-packages\import_export\admin.py", line 125, in process_dataset
return resource.import_data(dataset,
File "C:\users\iv\mip\mip_env\lib\site-packages\import_export\resources.py", line 771, in import_data
return self.import_data_inner(
File "C:\users\iv\mip\mip_env\lib\site-packages\import_export\utils.py", line 25, in __exit__
self.context_manager.__exit__(*args)
File "C:\users\iv\mip\mip_env\lib\site-packages\django\db\transaction.py", line 246, in __exit__
connection.commit()
File "C:\users\iv\mip\mip_env\lib\site-packages\django\utils\asyncio.py", line 33, in inner
return func(*args, **kwargs)
File "C:\users\iv\mip\mip_env\lib\site-packages\django\db\backends\base\base.py", line 266, in commit
self._commit()
File "C:\users\iv\mip\mip_env\lib\site-packages\django\db\backends\base\base.py", line 242, in _commit
return self.connection.commit()
File "C:\users\iv\mip\mip_env\lib\site-packages\django\db\utils.py", line 90, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "C:\users\iv\mip\mip_env\lib\site-packages\django\db\backends\base\base.py", line 242, in _commit
return self.connection.commit()
Exception Type: IntegrityError at /admin/mip_apps/ithardware/process_import/
Exception Value: FOREIGN KEY constraint failed
Based on your code sample, the import process will look for a field called it_hardware_department in the import file (and we can see that it is there). During import, it will attempt to find the FK relation in Department by doing a simple get(name=<value in column>. It will store this value in ITHardware.it_hardware_department - however this won't work because this isn't a valid model field. You should rename this to it_hardware_department (which you said you did). The fact that shows up in the preview screen tells me that this worked ok.
The 'FK contraint' failed error says that you have tried to write to the table with an invalid FK relationship. I suggest run the debugger or add a print to inspect the object before it is saved. It is likely that one of your required Foreign Keys will be empty here. I don't think it is it_hardware_department because this has a value in the preview. Are there other FKs in your model which are not listed?
I coded a field(a) on classA which is to automatically take the contents of another field(b) in another classB
After updating my own developing on a module I tried to fill in a form on tryton, then I tried to save the form.
But there was an error
Traceback (most recent call last):
File "/trytond/wsgi.py", line 104, in dispatch_request
return endpoint(request, **request.view_args)
File "/trytond/protocols/dispatcher.py", line 48, in rpc
request, database_name, *request.rpc_params)
File "/trytond/wsgi.py", line 72, in auth_required
return wrapped(*args, **kwargs)
File "/trytond/protocols/wrappers.py", line 131, in wrapper
return func(request, pool, *args, **kwargs)
File "/trytond/protocols/dispatcher.py", line 197, in _dispatch
result = rpc.result(meth(*c_args, **c_kwargs))
File "/trytond/model/modelsql.py", line 832, in read
getter_results = field.get(ids, cls, field_list, values=result)
File "/trytond/model/fields/function.py", line 106, in get
return dict((name, call(name)) for name in names)
File "/trytond/model/fields/function.py", line 106, in <genexpr>
return dict((name, call(name)) for name in names)
File "/trytond/model/fields/function.py", line 101, in call
return dict((r.id, method(r, name)) for r in records)
File "/trytond/model/fields/function.py", line 101, in <genexpr>
return dict((r.id, method(r, name)) for r in records)
File "/trytond/modules/module_designing/design.py", line 15702, in On_change_design
('Description', '=', self.id),
ValueError: not enough values to unpack (expected 1, got 0)
, the method mentioned on the error is this : (this method I used it on my field(b) on a class B to call another field(a) on another class A)
def On_change_design(self,Name):
Design = Pool().get('design.classA')
design, = Design.search([
('classB', '=', self.id),
])
return design.id
field(b) = fields.Function(fields.Many2One('design.classA', 'test'), 'On_change_design')
the field(b) which will take the contain of the field(a)
this is how I was coded the field(a):
field(a) = fields.Function(fields.Char('area '),'on_change_parameters')
Any help will be appreciated, I want to know what's wrong and what I should do.
Or can anyone help me and tell how I can code the method onchange to make the field(b) take automatically the contents of another field(a) from another class(a)
Function fields are computed after you save. On your function you are performing a search into a related table and unpacking the result. This has no problem when the search returns a single record but in your case the search does not return any record so this makes the code crash.
You should use a safer code, that tests if the serach return any result before unpacking. Something like this:
def on_change_design(self,Name):
Design = Pool().get('design.classA')
designs = Design.search([
('classB', '=', self.id),
], limit=1)
if designs:
design, = designs
return design.id
return None
Note that I also added a limit on the search to ensure a maximum of one record is returned. This will also prevent to crash when multiple records are returned but you may want a diferent behaviour. I also added a explicit None return to make it clar that function will return None when no search is found.
Here's my models.py:
from django.db import models
class Location(models.Model):
location_name = models.CharField(max_length=100)
def __unicode__(self):
return self.location_name
class Menu(models.Model):
location = models.ManyToManyField(Location)
restaurant_name = models.CharField(max_length=200)
dish_category = models.CharField(max_length=100)
dish_name = models.CharField(max_length=200)
VNV_tag = models.CharField(max_length=100)
quantity = models.CharField(max_length=10, default='FULL')
price = models.CharField(max_length=5, default=0)
def __unicode__(self):
return self.restaurant_name
I am trying to populate my database from an excel file using xlrd python module.
Here's my populate_db.py script:
import os
import xlrd
from menusearch.models import Menu, Location
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'midnitepro.settings')
import django
django.setup()
def populate():
book = xlrd.open_workbook('/Users/Sahil/Desktop/MNFP1.xlsx')
sheet = book.sheet_by_index(0)
count1 = 0
while count1<sheet.nrows:
value_list = []
count2 = 0
while count2<sheet.ncols:
value_list.append(sheet.row_values(count1, start_colx=count2, end_colx=count2+1))
count2 +=1
add_menuitem(value_list)
count1 += 1
def add_menuitem(value_list):
split_query = []
m = Menu.objects.create()
value_list = [str(x[0]).encode('utf-8') for x in value_list if x]
m.restaurant_name = (value_list[0])
m.dish_category = (value_list[1])
m.dish_name = (value_list[2])
m.VNV_tag = (value_list[3])
m.quantity = (value_list[4])
m.price = (value_list[5])
# m.location.add(int(value_list[6]))
split_query = (value_list[6]).split(",")
for sq in split_query:
l = Location.objects.get_or_create(location_name=sq)
try:
m.location.add(l)
except ValueError:
print "Problem Adding Location to Menu."
m.save()
if __name__ == '__main__':
print "Starting population script..."
from menusearch.models import Menu, Location
populate()
Now when I run the populate_db.py script, the output on the terminal reads: "Problem Adding Location to Menu.". I see that the problem exists here in the populate_db script: m.location.add(l)
But this queryset is in line with the syntax given here: https://docs.djangoproject.com/en/1.8/topics/db/examples/many_to_many/
After removing the try/except, my traceback reads:
TypeError: int() argument must be a string or a number, not 'Location'
Please explain what is happening here.
And how to properly add a a value to the ManyToManyField via a queryset.
Possible duplicate: Django Error: TypeError: int() argument must be a string or a number, not 'BuildsTable'
But I would still like to know the answer in my case as I'm using a ManyToManyField.
Full traceback:
l= (<Location: Indiranagar>, False)
Inside Loop - sq= Indiranagar
Traceback (most recent call last):
File "populate_db.py", line 62, in <module>
populate()
File "populate_db.py", line 23, in populate
add_menuitem(value_list)
File "populate_db.py", line 50, in add_menuitem
m.location.add(l)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/fields/related.py", line 973, in add
self._add_items(self.source_field_name, self.target_field_name, *objs)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/fields/related.py", line 1079, in _add_items
'%s__in' % target_field_name: new_ids,
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/query.py", line 679, in filter
return self._filter_or_exclude(False, *args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/query.py", line 697, in _filter_or_exclude
clone.query.add_q(Q(*args, **kwargs))
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1304, in add_q
clause, require_inner = self._add_q(where_part, self.used_aliases)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1332, in _add_q
allow_joins=allow_joins, split_subq=split_subq,
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1194, in build_filter
lookups, value)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/fields/related.py", line 1745, in get_lookup_constraint
root_constraint.add(lookup_class(targets[0].get_col(alias, sources[0]), value), AND)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/lookups.py", line 96, in __init__
self.rhs = self.get_prep_lookup()
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/lookups.py", line 134, in get_prep_lookup
return self.lhs.output_field.get_prep_lookup(self.lookup_name, self.rhs)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/fields/__init__.py", line 729, in get_prep_lookup
return [self.get_prep_value(v) for v in value]
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/fields/__init__.py", line 985, in get_prep_value
return int(value)
TypeError: int() argument must be a string or a number, not 'Location'.
To add a value to a ManyToManyField, you need to add the objects by passing them as arguments.
add(obj1, obj2, obj3, ...)
This will add the specified objects to the related object set.
You can call the add() like below:
menu_object.location.add(loc_obj1, loc_obj2, ...)
In your case, you need to do:
l = Location.objects.get_or_create(location_name=sq)[0]
You need to access the instance by index 0 as get_or_create returns a tuple (instance, created). Then pass this instance to the add() method.
Note:
Using add() with a many-to-many relationship will not call any .save() for each object, but rather create the relationships using .bulk_create().
I understand that Rahul Gupta has answered this already. But on a more theoretical level I think this is what happened when you use get_or_create here:
l = Location.objects.get_or_create(location_name=sq)
It returns a Tuple, and hence you have to call it's first element by modifying it to:
l = Location.objects.get_or_create(location_name=sq)[0]
Which returns only the index element of the tuple/dictionary!
I'm storing file paths as relative paths in the database, but I'm then using hybrid properties to turn in into an absolute path when its mapped. When I query using this property it throws an error. Here's the model:
class File(Base):
__tablename__ = 'files'
...
_f_path = Column(Unicode(30))
...
#hybrid_property
def f_path(self):
env = shelve.open('environment')
return os.path.join(env['project_dir'], self._f_path)
#f_path.setter
def f_path(self, _f_path):
self._f_path = _f_path
When I run this query (where ref is a unicode string):
session.query(File).filter_by(f_path=ref).first()
It gives me this error:
File "/Users/Ben/Dropbox/Giraffe/giraffe_server/giraffe/file_handlers/maya.py", line 135, in process_file
rf = session.query(File).filter_by(f_path=str(ref)).first()
File "build/bdist.macosx-10.7-intel/egg/sqlalchemy/orm/query.py", line 1211, in filter_by
for key, value in kwargs.iteritems()]
File "build/bdist.macosx-10.7-intel/egg/sqlalchemy/orm/util.py", line 597, in _entity_descriptor
return getattr(entity, key)
File "build/bdist.macosx-10.7-intel/egg/sqlalchemy/ext/hybrid.py", line 681, in __get__
return self.expr(owner)
File "/Users/Ben/Dropbox/Giraffe/giraffe_server/giraffe/model.py", line 133, in f_path
print "\n\n\n[model.py:File#f_path hybrid_property] returning: ", os.path.join(env['project_dir'], self._f_path)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.py", line 66, in join
if b.startswith('/'):
File "build/bdist.macosx-10.7-intel/egg/sqlalchemy/sql/expression.py", line 3426, in __nonzero__
raise TypeError("Boolean value of this clause is not defined")
TypeError: Boolean value of this clause is not defined
Your hybrid property must return a sql expression; yours does not, it returns a python string instead.
To resolve that for this case, don't do the path join in python but in a SQL expression instead:
return env['project_dir'] + os.path.sep + self._f_path
which will resolve to self._f_path.__radd__(result_of_project_dir_plus_os_path_sep), which can be used both in queries and as a return value.