-
Notifications
You must be signed in to change notification settings - Fork 400
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SQLAlchemy model primary key column attribute name must match column name #78
Comments
SHA: 738e673 removes the primary key functionality and the id from the factory in the tests. This means the database is given responsibility for setting automatic/sequence keys. This avoids the case I reported above as well as other cases where there are multi-column primary keys which would confuse the code I removed. Cases such as where there are multiple integer primary keys where only one of them is serial or where one of them is an integer and the other a non-integer. A couple of the tests are broken in my example but that is because the intended behaviour has now changed so the assumptions these test make seem wrong to me. However I left them broken because I suspect there might be some concept in factory boy these are covering, specifically the use case of StandardFactory.reset_sequence(). |
Thanks for the PR. I see two issues around this whole
I'll try to find a way to introspect the schema so that factory_boy can find out:
Actually, I have the same kind of issues with |
What are the reasons that this should be factory_boy's responsibility? Shouldn't users be responsible for ensuring they craft and use factories in a way that doesn't create conflicts with unique fields? |
A colleague and I just ran into this same issue (we have aliased primary keys) and it seems like we're able to work around it with a simple subclass of
This seems to satisfy the requirement in the common case (either an auto-increment or single numerical PK exists). This seems to mitigate issues The downside of this is that it isn't thread-safe, but I don't think the old implementation was thread-safe either so perhaps that's not an issue. That said, wrapping this is a mutex could be easy enough. If this is a reasonable fix I'd happily create a PR including it. |
@steder and i poked at it some more, this looks more like what you were trying to achieve originally, but this way, it works for columns that have been aliased. @steder and i talked more about the previous solution, and it doesn't really make sense to have the class keep track of max_id, in case records get inserted from somewhere other than factory_boy. from sqlalchemy.sql import column
from sqlalchemy import func
class BetterThanMikes(SQLAlchemyModelFactory):
@classmethod
def _setup_next_sequence(cls, *args, **kwargs):
session = cls.FACTORY_SESSION
model = cls.FACTORY_FOR
pk = column(model.__mapper__.primary_key[0].name)
max_pk = session.query(model, func.max(pk)).one()[0]
if isinstance(max_pk, int):
return max_pk + 1 if max_pk else 1
else:
return 1 |
I started using @amoffat's solution above (thanks!), but ran into an error where sometimes
I modified the function to explicitly specify the model's table along with the pk column, and it seems to work: from factory.alchemy import SQLAlchemyModelFactory
from sqlalchemy.sql import column
from sqlalchemy import func
class PKFixedSQLAlchemyModelFactory(SQLAlchemyModelFactory):
@classmethod
def _setup_next_sequence(cls, *args, **kwargs):
session = cls.FACTORY_SESSION
model = cls.FACTORY_FOR
pk = column(model.__mapper__.primary_key[0].name)
max_pk = session.query(model, func.max('{}.{}'.format(model.__tablename__, pk))).one()[0]
if isinstance(max_pk, int):
return max_pk + 1 if max_pk else 1
else:
return 1 |
Related to issues #78, #92, #103, #111, #153, #170 The default value of all sequences is now 0; the automagic ``_setup_next_sequence`` behavior of Django/SQLAlchemy has been removed. This feature's only goal was to allow the following scenario: 1. Run a Python script that uses MyFactory.create() a couple of times (with a unique field based on the sequence counter) 2. Run the same Python script a second time Without the magical ``_setup_next_sequence``, the Sequence counter would be set to 0 at the beginning of each script run, so both runs would generate objects with the same values for the unique field ; thus conflicting and crashing. The above behavior having only a very limited use and bringing various issues (hitting the database on ``build()``, problems with non-integer or composite primary key columns, ...), it has been removed. It could still be emulated through custom ``_setup_next_sequence`` methods, or by calling ``MyFactory.reset_sequence()``.
This issue has been fixed in 13d310f, and will be part of the 2.5.0 release. |
Had to give up on getting the factory_boy-generated object to give me an ID and I just had to query the whole thing again. :| See also: - FactoryBoy/factory_boy@738e673 - FactoryBoy/factory_boy#78
So we've got a set of SQLAlchemy models like so (don't ask why, it makes me sad).
When using a factory for the class we get:
A full example:
The text was updated successfully, but these errors were encountered: