citusdata / citusdata/django-multitenant

django.db.utils.ProgrammingError: foreign key referenced-columns list must not contain duplicates

Open
#202 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
823
Forks
126
PR merge metrics
No merged PRs in 30d

Description

Hello all,

**Quick summary**

I'm getting

`django.db.utils.ProgrammingError: foreign key referenced-columns list must not contain duplicates` when I attempt to run any migrations at all on a new starter project.}

I think there must be something basic I'm missing, but I can't find it in issues or documentation.

**Detailed**

I'm trying to get a basic starter case going and I can't get a single migration to work, so I think I'm missing something simple

```
from django_multitenant.models import TenantModel
from django.db import models

class Account(TenantModel):
name = models.CharField(max_length=255)
contact_info = models.TextField()

class TenantMeta:
tenant_field_name = "id"

class Meta:
unique_together = ["id"]

def __str__(self):
return self.name
```

I create a basic Account tenant.

I then try to add it to the users with database backend enabled. I get a basic user migration

```
class User(TenantModelMixin, AbstractBaseUser, PermissionsMixin, IndexedTimeStampedModel):
email = models.EmailField(max_length=255, unique=True)
is_staff = models.BooleanField(
default=False, help_text=_("Designates whether the user can log into this admin site.")
)
is_active = models.BooleanField(
default=True,
help_text=_(
"Designates whether this user should be treated as "
"active. Unselect this instead of deleting accounts."
),
)
name = models.CharField(max_length=255)
# Custom fields
account = models.ForeignKey(
Account,
on_delete=models.CASCADE,
related_name="users",
null=True,
blank=True,
)
tenant_id = "account_id"
objects = UserManager()

USERNAME_FIELD = "email"

class Meta:
unique_together = ["id", "account"]

```
```

class Migration(migrations.Migration):
initial = True

dependencies = [
("auth", "0012_alter_user_first_name_max_length"),
("accounts", "0001_initial"),
]

operations = [
migrations.CreateModel(
name="User",
fields=[
(
"id",
models.BigAutoField(
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
),
),
("password", models.CharField(max_length=128, verbose_name="password")),
(
"last_login",
models.DateTimeField(blank=True, null=True, verbose_name="last login"),
),
(
"is_superuser",
models.BooleanField(
default=False,
help_text="Designates that this user has all permissions without explicitly assigning them.",
verbose_name="superuser status",
),
),
(
"created",
model_utils.fields.AutoCreatedField(
db_index=True,
default=django.utils.timezone.now,
editable=False,
verbose_name="created",
),
),
(
"modified",
model_utils.fields.AutoLastModifiedField(
db_index=True,
default=django.utils.timezone.now,
editable=False,
verbose_name="modified",
),
),
("email", models.EmailField(max_length=255, unique=True)),
(
"is_staff",
models.BooleanField(
default=False,
help_text="Designates whether the user can log into this admin site.",
),
),
(
"is_active",
models.BooleanField(
default=True,
help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.",
),
),
(
"account",
django_multitenant.fields.TenantForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="users",
to="accounts.account",
),
),
(
"groups",
models.ManyToManyField(
blank=True,
help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.",
related_name="user_set",
related_query_name="user",
to="auth.group",
verbose_name="groups",
),
),
(
"user_permissions",
models.ManyToManyField(
blank=True,
help_text="Specific permissions for this user.",
related_name="user_set",
related_query_name="user",
to="auth.permission",
verbose_name="user permissions",
),
),
],
options={
"unique_together": {("id", "account")},
},
bases=(django_multitenant.mixins.TenantModelMixin, models.Model),
),
]

```

And it fails because of the double account_id: `foreign key referenced-columns list must not contain duplicates`

```
CREATE TABLE "users_user" ("id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY, "password" varchar(128) NOT NULL, "last_login" timestamp with time zone NULL, "is_superuser" boolean NOT NULL, "created" timestamp with time zone NOT NULL, "modified" timestamp with time zone NOT NULL, "email" varchar(255) NOT NULL UNIQUE, "is_staff" boolean NOT NULL, "is_active" boolean NOT NULL, "account_id" bigint NULL);
CREATE TABLE "users_user_groups" ("id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY, "user_id" bigint NOT NULL, "group_id" integer NOT NULL);
CREATE TABLE "users_user_user_permissions" ("id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY, "user_id" bigint NOT NULL, "permission_id" integer NOT NULL);

-- The bad lines:
ALTER TABLE "users_user" ADD CONSTRAINT "users_user_id_account_id_e2e2a14b_uniq" UNIQUE ("id", "account_id");
ALTER TABLE "users_user" ADD CONSTRAINT "users_user_account_id_account_i_985fcd95_fk_accounts_" FOREIGN KEY ("account_id", "account_id") REFERENCES "accounts_account" ("id", "id") DEFERRABLE INITIALLY DEFERRED;
```

I can't find any other issues related to this so I think I'm just missing something very simple. Could someone point me in the right direction?

Contributor guide

Open the contributing guide

Research direction

Start with the Account and User model definitions, especially TenantMeta, TenantForeignKey, and each model's unique_together, then inspect the generated initial migration and the PostgreSQL SQL shown in the report. Trace how the migration creates the foreign key and determine why account_id is emitted twice. Done means the starter project's migrations run successfully without duplicate referenced columns.

Written by the indexing model from the issue text.

Assessment

Tech stack
postgresql, python
Domain
backend, databases
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
32/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.