Li
Posted on September 16, 2020
For a model defined in Django,consider, a foreign key field pointed to User:
class Article(Model):
title = CharField()
content = TextField()
user = ForeignKey(to=get_user_model())
If article
is an instance of Article, article.user
would get a User instance(base on get_user_model()) based on the foreign key defined.
If you happen to a project where the data consistency is not well maintained, e.g., the admin had deleted several old users despite the data dependency. When calling article.user
, you may get a DoesNotExist error, mostly look like
DoesNotExist: User matching query does not exist.
From the source of Django, I found a comment in db/models/fields/related_descriptors.py:
# Assuming the database enforces foreign keys, this won't fail.
This means when dealing with the consistency of ForeignKey, Django tends to simply raise an error and leave it to the database admin. But in some cases, if we can resolve article.user
as a None object, it would be easier for the code to handle, or more compatible with other serializers/validators.
I monkey-patched the module with the following code:
from django.db.models.fields.related_descriptors import ForwardManyToOneDescriptor
def get_object(self, instance):
qs = self.get_queryset(instance=instance)
# Assuming the database enforces foreign keys, this won't fail.
return qs.filter(self.field.get_reverse_related_filter(instance)).first()
ForwardManyToOneDescriptor.get_object = get_object
The code replaces query_set.get
with query_set.first
, no exceptions raised but return a None when object does not exist. By the way, when if the uniqueness of the foreign key object can be assured, e.g. the foreign key is the primary key in the table related, query_set.first
is faster than query_set.get
, since it stops scanning the table on the first row matched.
Posted on September 16, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 29, 2024