Generic Relations and Unlimited Phone Numbers


I read your article about generic relations and the fact that it will slow things down and become more complex. I need to be able to store unlimited amount of phone numbers per user. Like Google Contacts let’s you do.
I don’t see another way around this?

Also, how would I output that in the Admin?


I think I got it figured out, just worried about performance.

One issue I am having is that when I go to add a user in the admin, under the Phones section it wants a user each time. How do I not show that and make sure it puts in the ID of the new user that is being created?

(Arvie San) #3

Is many-to-many field not applicable on the situation? since you just need to add one type of data which is phone number?


No, because one person can have many phones, but many people can’t have the same phone.

(Vitor Freitas) #5

Just an associative model with a foreign key pointing to the user model would do:

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

class Phone(models.Model):
    person = models.ForeignKey(Person, on_delete=models.CASCADE, related_name='phones')
    phone = models.CharField(max_length=30, unique=True)

Then on Django Admin you can let the users add the phones directly on the person views:

class PhoneInline(admin.TabularInline):
    model = Phone

class PersonAdmin(admin.ModelAdmin):
    list_display = ['first_name', 'last_name']
    inlines = [PhoneInline,]

You can also use admin.StackedInline instead of admin.TabularInline


Wow, ok, thanks. Will try that. Easier than what i was doing.


ok, so I got this work as above. One problem I see is that when the new phone numbers are shown, it shows the actual PK which is a UUID. Assume it’s coming from the str_() in the model. How do I get it to show likes it was before, which is the count. Phone #1, #2 etc.


class Phone(models.Model):
    (1, 'home'),
    (2, 'mobile'),
    (3, 'fax'),
    (4, 'other'),
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
user = models.ForeignKey(User, on_delete=models.CASCADE)
phone_type = models.PositiveSmallIntegerField(choices=PHONE_TYPE_CHOICES, null=False, blank=False)
phone_number = PhoneNumberField(blank=True, null=True)
phone_extension = models.CharField(max_length=10, blank=True, null=True, verbose_name=_("Phone Ext."))

class Meta:
    unique_together = ('user', 'phone_type', 'phone_number')

def __str__(self):
    return str(

from django.contrib import admin
from django.contrib.auth import admin as auth_admin, get_user_model
from phonenumber_field.formfields import PhoneNumberField
from phonenumber_field.widgets import PhoneNumberPrefixWidget

from corfix.users.models import Phone

User = get_user_model()

class PhoneInline(admin.StackedInline):
    model = Phone
    formfield_overrides = {
    PhoneNumberField: {
        'widget': PhoneNumberPrefixWidget

class UserAdmin(auth_admin.UserAdmin):
inlines = [PhoneInline, ]
fieldsets = (("User", {
    "fields": ("name", "client", "user_type"),
    }),) + auth_admin.UserAdmin.fieldsets
list_display = ["username", "name", "client", "user_type"]
search_fields = ["name", "username", "email"]