Create after a filter or in custom manager

As we use Django, we hit something that multiple devs thought was counter-intuitive. Say you call create on a queryset that has already been filtered some how. All of that filtering information is ignored with the create. For example if you did something like User.objects.filter(is_staff=True).create(first_name='StaffGuy') then the created User will not have is_staff set to True. This becomes even more counter intuitive if you have a custom Manager or custom QuerySet that filter. Perhaps this is because arbitrary filters may not be as easy to apply, but I tried to find anything in the documentation for create hinting this behavior, but couldn’t. Are we the only ones feeling like this is a pitfall? Is there a similar discussion elsewhere about this? This applies to create, get_or_create, update_or_create etc.

The create method is documented as creating a new instance of an object - not that it in any way is associated with any existing instance.

It is not used to duplicate or create additional instances from existing instances. There is nothing documenting that it works that way.

I think you’re making some incorrect assumptions about how the ORM works - perhaps because you’re trying to draw an analogy from a different system.

I suspect you are trying to do something outside the design of Django. It also seems illogical to expect a new instance of User to have fields that are automatically set without defining how that magic will happen. Setting is_staff automatically shouldn’t even be happening. Default=False may suffice if you want is_staff to be set automatically when instantiating User.

Filter is filtering a queryset of the object (User) and not the single instance of User (but a collection of Users if you will). Therefore, Filter, has nothing to contribute when creating a new instance.

You will do well to specify the initial values of the fields when instantiating User. eg.
User.objects.filter(is_staff=True).create(first_name='StaffGuy', is_staff=True)

The is_staff field needs specific attention and should not be automatic.

You are probably trying to do the following:

if not User.objects.filter(is_staff=True).exists():
    user = User(first_name='StaffGuy', is_staff=True)

I suppose what we got stuck on is the way in which many methods on query set ‘chain’ For example, you can chain a filter, exclude, etc and then call .update(), .delete(), .exists() etc. But for these create methods, there is no chaining, even if you are calling it on a queryset that was created by chaining.

I understand it would not make sense in the general case, but we didn’t gather from the documentation how chaining works (or does not) with create. The only part that seems relevant is this small part " You can specify more complex conditions for the retrieved object by chaining get_or_create() with filter() and using Q objects".

I suppose I’m suggesting that somehow briefly specifying that chaining is ignored or not relevant for create and other similar methods would have clarified it for us.

What is confusing to me is that the filter part of this example is useless. There is no point to it, does it have any effect at all? If no, perhaps it shouldn’t be allowed. Maybe calling create on a filtered query should be warned against as not valuable.

I don’t know why it shouldn’t be allowed - while it doesn’t have the exact sematics that you might think that it could have, doesn’t necessarily mean that it is not valuable to someone.

Exactly as written and limited to what is shown here, in the absence of any other operation? No.

But, you can’t tell from that one line whether or not there is a custom manager being used containing some type of side-effect - or ignore the possibility that there may be more to this filter than just a straight field comparison.

The point is that while this specific example, limited in what is shown here has no apparent value, that does not mean that there can’t be a more complex or intricate query that does have value being chained to the create.

The docs define what create does, what objects it works on and what it uses as input - as does every other function within the ORM API. Whether or not that api is useful to you is something only you can determine.

Fair enough. My suggestion was that in the usual and common cases, chaining a create, say after filters, doesn’t use any context or info from the chain, it is discarded and not relevant. And the create docs do not mention chaining at all or what happens. I suppose it may be fair to say that the absence of that means chaining isn’t relevant. I’d be interested if we’re the only ones that see the user example given above and assume incorrectly the filter influences the create in simple cases.

Ah I found the example that may have confused us. Related managers: Related objects reference | Django documentation | Django That create does take into account context. However, that is probably a false path we went down.