这就是我要做的事情:
def test_basic_addition(self):
# create field
f = models.ManyToManyField(to=X, related_name='bar')
f.contribute_to_class(Y, 'x')
# create table
field = Y._meta.get_field_by_name('x')[0]
through = field.rel.through
fields = tuple((field.name, field) for field in through._meta.fields)
db.create_table(through._meta.db_table, fields)
db.create_unique(through._meta.db_table,
['%s_id' % name for name, f in fields
if isinstance(f, models.ForeignKey)])
x = X(name='foo')
x.save()
y = Y()
y.save()
y.x.add(x)
print y.x.all()
抛出的异常是:
E
======================================================================
ERROR: test_basic_addition (test_app.tests.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/jpic/test_project/test_app/tests.py", line 41, in test_basic_addition
print y.x.all()
File "/home/jpic/env/local/lib/python2.7/site-packages/django/db/models/manager.py", line 116, in all
return self.get_query_set()
File "/home/jpic/env/local/lib/python2.7/site-packages/django/db/models/fields/related.py", line 543, in get_query_set
return super(ManyRelatedManager, self).get_query_set().using(db)._next_is_sticky().filter(**self.core_filters)
File "/home/jpic/env/local/lib/python2.7/site-packages/django/db/models/query.py", line 621, in filter
return self._filter_or_exclude(False, *args, **kwargs)
File "/home/jpic/env/local/lib/python2.7/site-packages/django/db/models/query.py", line 639, in _filter_or_exclude
clone.query.add_q(Q(*args, **kwargs))
File "/home/jpic/env/local/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1250, in add_q
can_reuse=used_aliases, force_having=force_having)
File "/home/jpic/env/local/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1122, in add_filter
process_extras=process_extras)
File "/home/jpic/env/local/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1316, in setup_joins
"Choices are: %s" % (name, ", ".join(names)))
FieldError: Cannot resolve keyword 'bar' into field. Choices are: id, name, users
----------------------------------------------------------------------
Ran 1 test in 0.017s
FAILED (errors=1)
Destroying test database for alias 'default'...
del X._meta._name_map
没有做到这一点,但我猜这是正常的,因为它是来自另一个模型Y的反向场。
无论如何,您可以查看我的问题test_project,然后在您的工作副本中运行./manage.py test test_app
以重现此问题。
答案 0 :(得分:0)
解决方案是对Django的AppCache实施疯狂的攻击,显然是is a pain。
最干净的解决方案是使用SQLAlchemy,这是一个可怕的概念证明,在重构和一些锁定功能之后将成为python包:
import unittest
import sqlalchemy as sa
from sqlalchemy import orm
from sqlalchemy.ext.declarative import declarative_base
from alembic.operations import Operations
from alembic.migration import MigrationContext
Base = declarative_base()
engine = sa.create_engine('mysql://root:root@localhost/jpic')
Session = orm.sessionmaker(bind=engine)
session = Session()
conn = engine.connect()
ctx = MigrationContext.configure(conn)
op = Operations(ctx)
for table in ('person_car', 'cars', 'houses', 'persons'):
op.drop_table(table)
class PersonTest(unittest.TestCase):
def test_000_create_table(self):
self.__class__.Person = type('Person', (Base,), {'__tablename__': 'persons',
'id': sa.Column(sa.Integer, primary_key=True)})
self.__class__.Car = type('Car', (Base,), {'__tablename__': 'cars',
'id': sa.Column(sa.Integer, primary_key=True)})
self.__class__.House = type('House', (Base,), {'__tablename__': 'houses',
'id': sa.Column(sa.Integer, primary_key=True)})
Base.metadata.create_all(engine)
def test_001_create_unicode_field(self):
# create the column in the table - does not add it in the class
field = sa.Column('unicode_field', sa.Unicode(50))
op.add_column('persons', field)
# create the column in the class - was not done above
# a new instance to avoid conflicts
field = sa.Column('unicode_field', sa.Unicode)
self.__class__.Person.unicode_field = field
subject = self.__class__.Person(unicode_field='hello unicode field')
session.add(subject)
subject = session.query(self.__class__.Person).first()
self.assertEqual(subject.unicode_field, 'hello unicode field')
def test_002_create_foreign_key(self):
field = sa.Column('owner_id', sa.Integer, sa.ForeignKey('persons.id'))
op.add_column('houses', field)
# create fk
op.create_foreign_key('fk_house_owner', 'houses', 'persons', ['owner_id'], ['id'])
field = sa.Column('owner_id', sa.Integer, sa.ForeignKey('persons.id'))
relation = orm.relationship('Person',
backref=orm.backref('houses', lazy='dynamic'))
self.__class__.House.owner_id = field
self.__class__.House.owner = relation
owner = session.query(self.__class__.Person).first()
house = self.__class__.House()
house.owner = owner
session.add(house)
house = session.query(self.__class__.House).first()
self.assertEqual(house.owner, owner)
# also test the reverse relation
self.assertEqual(owner.houses.all(), [house])
def test_003_create_many_to_many(self):
association_table = sa.Table('person_car', Base.metadata,
sa.Column('person_id', sa.Integer, sa.ForeignKey('persons.id')),
sa.Column('car_id', sa.Integer, sa.ForeignKey('cars.id'))
)
Base.metadata.create_all(engine)
self.__class__.Person.cars = orm.relationship('Car',
secondary=association_table,
backref=orm.backref('persons', lazy='dynamic'))
user1 = session.query(self.__class__.Person).first()
user2 = self.__class__.Person()
session.add(user2)
car1 = self.__class__.Car()
session.add(car1)
car2 = self.__class__.Car()
session.add(car2)
user1.cars.append(car1)
car2.persons.append(user1)
session.commit()
fresh_user1 = session.query(self.__class__.Person).get(user1.id)
self.assertEqual(len(fresh_user1.cars), 2)
self.assertTrue(car1 in fresh_user1.cars)
self.assertTrue(car2 in fresh_user1.cars)
fresh_car1 = session.query(self.__class__.Car).get(car1.id)
self.assertEqual(fresh_car1.persons.all(), [user1])
请注意,这适用于mysql,但不适用于sqlite或postgres。
Hello Flask和SQLAlchemy B)