Skip to content
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

Allow relation _id fields to use a sequence #253

Merged
merged 5 commits into from Oct 30, 2021

Conversation

ashiazed
Copy link
Contributor

@ashiazed ashiazed commented Oct 24, 2021

Fixes #123

This change allows seq to be used on an ForeignKey or OneToOne.
I assume that in these cases the relations were made before hand and this type of recipe is used for assignment.

elif field.name not in self.model_attrs:
if (
not isinstance(field, ForeignKey)
or "{0}_id".format(field.name) not in self.model_attrs
or hasattr(field, "attname")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I swapped this to checking "attname" as it mirrors the same technique that Django uses internally.

and hasattr(field, "attname")
and field.attname in self.iterator_attrs
):
return False
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a fan of returning a False here rather than running through the conditions and falling back to the False at the end. The last 2 conditions catch this scenario and it was getting complicated to isolate the right case. Suggestions welcome.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I totally agree with you here @ashiazed, but I think this is a result of a major problem that is the fact that there's practically no abstractions under this major for field in fields loop.

I mean, this is done like that since the very beginning of the project and never was refactored. But today, it's more clear to me that we should have a piece of code to receive a field and generate a value/skip it. Baker class would only trust that everything happened as expected. If we had such object, I feel that these validations wouldn't be all grouped together like that.

baker.make(Profile, _quantity=3)
seq_user = user_recipe.extend(username="name", profile_id=seq(1))
user = seq_user.make()
assert user.profile_id == 2
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just want to triple check here as I thought it was a tad unintuitive, the first generated number is 2 not 1?
Just want to make sure this didn't run through an unnecessary yield somewhere.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's correct. As you can see here, the iteration starts at start or increment_by (if start is falsey). Therefore, the only way to begin iteration from 0 is to supply a value of -1 and to begin from 1 to provide a value of 0 (which is definitely not intuitive).

I am not the original author, so I cannot speak to the intent of this code, however, it seems like a case of just trying to accommodate too many uses without a clear interface for each specific one. The code could probably be improved, however, most uses I have seen come in the form of str values with appended integers (which will "rightfully" start at Foo 1 by default). That is most likely the reason the int/float case hasn't gotten too much attention, but that is a guess on my part.

@ashiazed
Copy link
Contributor Author

Happy Hacktoberfest 🎃

@ashiazed
Copy link
Contributor Author

@timjklein36 Tests should be passing now. I was being silly and passed in a hardcoded int as a PK in the tests and of course that doesn't play nice in postgres test db 🙄

Copy link
Member

@berinhard berinhard left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @ashiazed for this PR and the discussions you've raised too. Given our merge policies, I have to wait for other maintainer to approve this PR before I can merge it.

and hasattr(field, "attname")
and field.attname in self.iterator_attrs
):
return False
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I totally agree with you here @ashiazed, but I think this is a result of a major problem that is the fact that there's practically no abstractions under this major for field in fields loop.

I mean, this is done like that since the very beginning of the project and never was refactored. But today, it's more clear to me that we should have a piece of code to receive a field and generate a value/skip it. Baker class would only trust that everything happened as expected. If we had such object, I feel that these validations wouldn't be all grouped together like that.

Copy link
Collaborator

@timjklein36 timjklein36 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the discussion so far, this looks good to me.

@berinhard berinhard merged commit a32bdcc into model-bakers:main Oct 30, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Use of itertools.count to generate record ids in Recipe
3 participants