MiniGunnR
MiniGunnR

Reputation: 5800

How to inherit from ForeignKey to extend model field?

I am trying to create a custom ForeignKey. I have inherited from it and trying to override __init__ method to provide the positional arguments to and on_delete like the following:

from django.contrib.auth.models import User

class CurrentUserField(models.ForeignKey):
    def __init__(self, **kwargs):
        super().__init__(User, models.CASCADE, **kwargs)


class DemoModel(models.Model):
    owner = CurrentUserField()
    info = models.TextField()

It gives me the following error when I am running makemigrations:

TypeError: __init__() got multiple values for argument 'on_delete'

I can't seem to figure out what the problem is. I am only providing two values for two positional arguments.

Upvotes: 5

Views: 1054

Answers (1)

user459872
user459872

Reputation: 24562

Suppose if you pass User and on delete parameters in your owner field itself you could see how Django is converting its arguments.

EXAMPLE

from django.db import models
from django.contrib.auth.models import User


class CurrentUserField(models.ForeignKey):
    def __init__(self, *args, **kwargs):
        for i in args:
            print(i, "This is an argument")

        for j in kwargs.items():
            print(j, "This is a keyword argument")
        super().__init__(*args, **kwargs)


class DemoModel(models.Model):
    owner = CurrentUserField(User, on_delete=models.CASCADE)
    info = models.TextField()

OUTPUT

<class 'django.contrib.auth.models.User'> This is an argument
('on_delete', <function CASCADE at 0x103900400>) This is a keyword argument
('on_delete', <function CASCADE at 0x103900400>) This is a keyword argument
('to', 'auth.User') This is a keyword argument
('on_delete', <function CASCADE at 0x103900400>) This is a keyword argument
('to', 'auth.User') This is a keyword argument

as you can see Django is converting auth.User and models.CASCADE into a dictionary with keys to and on_delete respectively. i.e., {'to': 'auth.User', 'on_delete': <function CASCADE at 0x103900400>}.

So in your case you should set the default value for the keys to and on_delete to get the expected behaviour.

i.e.,

from django.db import models
from django.contrib.auth.models import User


class CurrentUserField(models.ForeignKey):
    def __init__(self, *args, **kwargs):
        kwargs.setdefault('to', User)
        kwargs.setdefault('on_delete', models.CASCADE)
        super().__init__(*args, **kwargs)


class DemoModel(models.Model):
    owner = CurrentUserField()
    info = models.TextField()

Upvotes: 4

Related Questions