В моделях Django, как поле внешнего ключа узнает, с каким полем сопоставить поле в другой модели?

Я понимаю, что делают внешние ключи, но мне трудно понять, почему это работает в Django.

У меня есть модель Project в файле 'app1/models.py'. Эта модель имеет ForeignKey с именем 'owner', который ссылается на модель Profile в моем файле 'app2/models.py'

Как поле 'owner' в модели Project узнает, что оно должно быть связано с полем 'user' в модели Profile, если я передаю только имя модели полю 'owner'? Мне кажется, что я должен передавать Profile.field или что-то вроде этого в модели Project:

owner = models.ForeignKey(Profile.user, null=True, blank=True ... )

Полный код модели из учебника Денниса Айви:

class Project(models.Model):
    owner = models.ForeignKey(Profile, null=True, blank=True, on_delete=models.SET_NULL)
    title = models.CharField(max_length=200) #null is default=False and is required
    description = models.TextField(null=True, blank=True) #for a bigger field, allows null(for db)/blank(for Django get/post)
    featured_image = models.ImageField(null=True, blank=True, default='default.jpg')
    demo_link = models.CharField(max_length=2000)
    source_link = models.CharField(max_length=2000, null=True, blank=True) #can be blank in db
    tags = models.ManyToManyField('Tag', blank=True) #quotes will ref other class after this one 
    vote_total = models.IntegerField(default=0, null=True, blank=True)
    vote_ratio = models.IntegerField(default=0, null=True, blank=True)
    created = models.DateTimeField(auto_now_add=True) #generate when model instance is created
    id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False) 

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True)
    name = models.CharField(max_length=200, blank=True, null=True)
    email = models.EmailField(max_length=500, blank=True, null=True)
    username = models.CharField(max_length=200, blank=True, null=True)
    location = models.CharField(max_length=200, blank=True, null=True)
    short_intro = models.CharField(max_length=200, blank=True, null=True)
    bio = models.TextField(blank=True, null=True)
    profile_image = models.ImageField(
        null=True, blank=True, upload_to='profiles/', default='profiles/user-default.png')
    social_github = models.CharField(max_length=200, blank=True, null=True)
    social_twitter = models.CharField(max_length=200, blank=True, null=True)
    social_linkedin = models.CharField(max_length=200, blank=True, null=True)
    social_youtube = models.CharField(max_length=200, blank=True, null=True)
    social_website = models.CharField(max_length=200, blank=True, null=True)
    created = models.DateTimeField(auto_now_add=True)
    id = models.UUIDField(default=uuid.uuid4, unique=True, 
                        primary_key=True, editable=False) 

Поле с внешним ключом не совпадает с другим полем в другой модели. оно совпадает с самой моделью.Допустим, вы хотите присвоить профиль с именем 'victor' новому объекту модели проекта, это будет выглядеть следующим образом:

from app_name.model import Project, Profile

profile1=Profile.objects.filter(name='victor').first()
new_project=Project(title='project 1',demolink='demo link',owner=profile1)

здесь мы присвоили объект пользователя свойству owner проекта, а не полю.

Поле Profile.User не является необходимым. Если вы хотите создать customUser, я советую вам изучить этот вопрос, иначе вы создадите себе множество проблем с аутентификацией. Вам придется создать для него менеджер моделей, после чего вы сможете приступить к настройке. Он должен выглядеть следующим образом:

from django.db import models
from django.contrib.auth.models import User, AbstractUser
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.base_user import BaseUserManager


class CustomUserManager(BaseUserManager):
    """
    Custom user model manager where email is the unique identifiers
    for authentication instead of usernames.
    """
    def create_user(self, username, password, **extra_fields):
        """
        Create and save a User with the given username and password.
        """
        if not username:
            raise ValueError(_('The Username must be set'))
        user = self.model(username=username, **extra_fields)
        user.set_password(password)
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', False)
        extra_fields.setdefault('is_active', True)
        user.save()
        return user

    def create_superuser(self, username, password, **extra_fields):
        """
        Create and save a SuperUser with the given username and password.
        """
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        extra_fields.setdefault('is_active', True)

        if extra_fields.get('is_staff') is not True:
            raise ValueError(_('Superuser must have is_staff=True.'))
        if extra_fields.get('is_superuser') is not True:
            raise ValueError(_('Superuser must have is_superuser=True.'))
        return self.create_user(username, password, **extra_fields)

class Profile(AbstractUser):

    objects = CustomUserManager()
    name = models.CharField(max_length=200, blank=True, null=True)
    email = models.EmailField(max_length=500, blank=True, null=True)
    location = models.CharField(max_length=200, blank=True, null=True)
    short_intro = models.CharField(max_length=200, blank=True, null=True)
    bio = models.TextField(blank=True, null=True)
    profile_image = models.ImageField(
        null=True, blank=True, upload_to='profiles/', default='profiles/user-default.png')
    social_github = models.CharField(max_length=200, blank=True, null=True)
    social_twitter = models.CharField(max_length=200, blank=True, null=True)
    social_linkedin = models.CharField(max_length=200, blank=True, null=True)
    social_youtube = models.CharField(max_length=200, blank=True, null=True)
    social_website = models.CharField(max_length=200, blank=True, null=True)
    created = models.DateTimeField(auto_now_add=True)
    id = models.UUIDField(default=uuid.uuid4, unique=True, 
                        primary_key=True, editable=False) 

Спасибо, Вик. Теперь я разрешил свою путаницу. ForeignKey указывает модель, но он всегда подключается к первичному ключу этой модели, поэтому мне не нужно указывать Project.title или Project.id. Затем, когда модель Review с ForeignKey выводится, она вызывает метод str модели Project, который перечисляет название. Я не знал, что вызывается метод str.

Я не включил метод str в свой пример кода, потому что не думал, что он имеет отношение к моей проблеме, но теперь я понимаю, что метод str является причиной того, что я вижу Project.title вместо Project.id.

def str(self): return self.title

Вернуться на верх