I'm trying to enable type hints for my Django REST project. I installed django-stubs and djangorestframework-stubs and I have the following mypy.ini file:
[mypy]
plugins =
mypy_django_plugin.main
mypy_drf_plugin.main
[mypy.plugins.django-stubs]
django_settings_module = "core.settings.base"
Some of the type hints do work; for example, if I have a variable inside of a method whose type is a model class, I get hints when I try to access a field or method defined on it.
However, if I try to access a Django-specific field on the model, for example a reverse relation, that does not typecheck and gives me an error. Moreover, if I try to access fields on a related model of my model variable, the related object has type Any
For example, with these two models:
class User(models.Model):
name = models.TextField()
role = models.ForeignKey(Role) # definition of Role model not relevant
class Badge(models.Model):
user = models.ForeignKey(User, related_name="badges")
then this will happen:
u: User = get_user()
print(u.name) # correctly hinted and typechecks
print(u.badges.all()) # type error
print(u.role.pk) # no hint on role.pk, role is Any
How do I get my project to correclty type check all the Django-specific features such as foreign key fields, querysets, and reverse relationships?
D:\zjm_code\basic_project>python manage.py syncdb
Error: One or more models did not validate:
topics.topic: Accessor for field 'content_type' clashes with related field 'Cont
entType.topic_set'. Add a related_name argument to the definition for 'content_t
ype'.
topics.topic: Accessor for field 'creator' clashes with related field 'User.crea
ted_topics'. Add a related_name argument to the definition for 'creator'.
topics.topic: Reverse query name for field 'creator' clashes with related field
'User.created_topics'. Add a related_name argument to the definition for 'creato
r'.
topicsMap.topic: Accessor for field 'content_type' clashes with related field 'C
ontentType.topic_set'. Add a related_name argument to the definition for 'conten
t_type'.
topicsMap.topic: Accessor for field 'creator' clashes with related field 'User.c
reated_topics'. Add a related_name argument to the definition for 'creator'.
topicsMap.topic: Reverse query name for field 'creator' clashes with related fie
ld 'User.created_topics'. Add a related_name argument to the definition for 'cre
ator'.
You have a number of foreign keys which django is unable to generate unique names for.
You can help out by adding "related_name" arguments to the foreignkey field definitions in your models.
Eg:
content_type = ForeignKey(Topic, related_name='topic_content_type')
See here for more.
http://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ForeignKey.related_name
Example:
class Article(models.Model):
author = models.ForeignKey('accounts.User')
editor = models.ForeignKey('accounts.User')
This will cause the error, because Django tries to automatically create a backwards relation for instances of accounts.User for each foreign key relation to user like user.article_set. This default method is ambiguous. Would user.article_set.all() refer to the user's articles related by the author field, or by the editor field?
Solution:
class Article(models.Model):
author = models.ForeignKey('accounts.User', related_name='author_article_set')
editor = models.ForeignKey('accounts.User', related_name='editor_article_set')
Now, for an instance of user user, there are two different manager methods:
user.author_article_set — user.author_article_set.all() will return a Queryset of all Article objects that have author == user
user.editor_article_set — user.editor_article_set.all() will return a Queryset of all Article objects that have editor == user
Note:
This is an old example — on_delete is now another required argument to models.ForeignKey. Details at What does on_delete do on Django models?
"If a model has a ForeignKey, instances of the foreign-key model will have access to a Manager that returns all instances of the first model. By default, this Manager is named FOO_set, where FOO is the source model name, lowercased."
But if you have more than one foreign key in a model, django is unable to generate unique names for foreign-key manager.
You can help out by adding "related_name" arguments to the foreignkey field definitions in your models.
See here:
https://docs.djangoproject.com/en/dev/topics/db/queries/#following-relationships-backward
If your models are inheriting from the same parent model, you should set a unique related_name in the parent's ForeignKey. For example:
author = models.ForeignKey('accounts.User', related_name='%(app_label)s_%(class)s_related')
It's better explained in th
If your models are inheriting from the same parent model, you should set a unique related_name in the parent's ForeignKey. For example:
author = models.ForeignKey('accounts.User', related_name='%(app_label)s_%(class)s_related')
It's better explained in the docs
I had a similar problem when I was trying to code a solution for a table that would pull names of football teams from the same table.
My table looked like this:
hometeamID = models.ForeignKey(Team, null=False, on_delete=models.CASCADE)
awayteamID = models.ForeignKey(Team, null=False, on_delete=models.CASCADE)
making the below changes solved my issue:
hometeamID = models.ForeignKey(Team, null=False, on_delete=models.CASCADE,related_name='home_team')
awayteamID = models.ForeignKey(Team, null=False, on_delete=models.CASCADE,related_name='away_team')
But in my case i am create a separate app for some functionality with same model name and field ( copy/paste ;) ) that's because of this type of error occurs i am just deleted the old model and code will work fine
May be help full for beginners like me :)
This isn't an ultimate answer for the question, however for someone it may solve the problem.
I got the same error in my project after checking out a really old commit (going to detached head state) and then getting the code base back up to date. Solution was to delete all *.pyc files in the project.
Do as the error message instructs you to:
Add a related_name argument to the
definition for 'creator'.
I have a foreign key, that when the object it references gets deleted will be filled with a default value via a callable on_delete=models.SET(callable).. However, I have problem with that because in the Django admin site I'm able to delete the callable value that it has passed to the foreign key and since my foreign key can't be null this is going to raise a server error which I don't like.. so I want to handle that error through the Django admin site itself if that is possible and I know it is.. also if you have better thoughts on this, I really appreciate your help.
As a temporary solution I had overrode the QuerySet > delete() method of the referenced model to skip deleting the object through the Django admin site bulk deletion. I'm sure that there is a better way than this.
The foreign key:
class Product(models.Model):
marektplace_tag = models.ForeignKey('tags.MarketplaceTag', on_delete=models.SET(default_marketplace_tag))
the callable:
# Model: Product
def default_marketplace_tag():
from tags.models import MarketplaceTag
tag = MarketplaceTag.objects.get_or_create(name='None')
return tag[0].id
The referenced model:
class MarketplaceTag(models.Model):
name = models.CharField(max_length=32, validators=[only_letters])
Model:
class MyModel(models.Model):
watermark_image = models.ImageField(null=True, blank=True, default=settings.WATERMARK_DEFAULT)
When I try to empty the field in the admin clicking on its checkbox, file is not deleted unless i remove default attribute from model! Why?
The default attribute in a model field has exactly that purpose:
If an object has no watermark_image attribute use the default image.
Why is this important?
Imagine if you have a field that cannot be blank, because it would otherwise lead to a database inconsistency.
For example if you would have a User model that has a profile_picture field.
When looping through a list of users in a list like this:
[user.profile_picture for user in User.objects.all()]
When you have a default value set on the model level for the profile_picture attribute you do not have to worry about this code. If you would not have that default value this code could raise an AttributeError for users that have no profile_picture set.
Therefore it is impossible to delete an attribute that has a default value set in the admin, because it would eliminate the purpose of the default keyword argument in the model attribute.
I added a Meta class which contains the following permissions but i don't know if its added just by only putting them in Meta class or i need to add something or assign them by a certain way. Here is my code :
class Contractor(models.Model):
contractor_verified = models.BooleanField(default=False)
Employer = models.OneToOneField(Employer)
job_title = models.CharField(max_length=50)
name = models.CharField(max_length=250)
class Meta:
permissions = (
("permission", "perm"),
("bid", "bid"),
("send_request_to_verifier", "send_request_to_verifier"),
("gain_points", "gain_points"),
("loose_points", "loose_points"),
)
and i am sorry if anything is not clear. I just need help on how to add custom permissions to an object which is not an instance of Django User
The django permissions system is only designed out of the box to support User and Group model permissions. From the django docs regarding object permissions: https://docs.djangoproject.com/en/1.3/topics/auth/#handling-object-permissions
Django's permission framework has a foundation for object permissions,
though there is no implementation for it in the core. That means that
checking for object permissions will always return False or an empty
list (depending on the check performed).
If you are looking for generic object-level permissions, there are a slew of available packages here: http://pypi.python.org/pypi?%3Aaction=search&term=django+permissions&submit=search
Some of these simply implement the model level permissions, and some let you define a per instance permission.