无法连接两个Django模型

问题描述 投票:0回答:1

我正在建立一个论坛网站,我有以下模型:

class Profile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE,     related_name='profile', null=True, blank=True)
    avatar = models.ImageField(upload_to='avatars/', null=True, blank=True)
    football_club = models.CharField(max_length=100)
    location = models.CharField(max_length=100, blank=True)


class CustomUser(AbstractBaseUser, PermissionsMixin):
    userprofile = models.OneToOneField(Profile, on_delete=models.CASCADE, related_name='user_profile',    null=True, blank=True)
    username = models.CharField(max_length=150, unique=True)
    email = models.EmailField(unique=True, null=False)
    created_at = models.DateTimeField(default=timezone.now)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)
    post_count = models.PositiveIntegerField(default=0)

   
    USERNAME_FIELD = 'username'
    REQUIRED_FIELDS = []

    objects = CustomUserManager()

    def __str__(self):
        return self.username

自定义用户字段是在注册过程中输入的,而个人资料字段应该在网站的/个人资料页面上进行选择性编辑。

两种模型的形式表示为

{{ form.as_p }} 

在相应的html文件中。

两种表单都在 forms.py 文件中设置:

from django import forms
from django.contrib.auth.forms import UserCreationForm
from .models import CustomUser, Profile

class SignUpForm(UserCreationForm):
    class Meta:
        model = CustomUser
        fields = ['username', 'email']


class ProfileForm(forms.ModelForm):
    class Meta:
        model = Profile
        fields = ['avatar', 'football_club', 'location']

我的views.py 文件中有以下函数/类:

class SignUpView(CreateView):
    form_class = SignUpForm
    template_name = 'accounts/signup.html'
    success_url = reverse_lazy('login'))

@login_required
def profile(request):
    profile = request.user.userprofile
    print("Profile: ", profile)
    if request.method == 'POST':
        form = ProfileForm(request.POST, request.FILES, instance=profile)
        if form.is_valid():
            form.save()
            return redirect('profile')
    else:
        form = ProfileForm(instance=profile)
    return render(request, 'accounts/profile.html', {'form': form})

但这两个模型实际上并没有相互联系。我在我的 html 模板页面之一中尝试了以下操作:

<ul>
    <li><h3>{{ post.author.username }}</h3></li>
    <li>Posts: {{ post.author.post_count }}</li>
    <li>Club: {{ post.author.userprofile.football_club }}</li>
</ul>

我的用户名和帖子计数显示正确,但俱乐部字段仍然为空,尽管 Football_club 和位置已存储到数据库中。

我尝试编辑 profile.html 中已有的 Football_club 和位置字段,但它只是在数据库中创建另一个模型实例,而不是编辑。

另外,在 python shell 中我尝试了以下操作:

>>> from accounts.models import Profile, CustomUser
>>> lastprofile = Profile.objects.last()
>>> print(lastprofile.football_club)
Inter
>>> print(lastprofile.location)
Milan
>>> print(lastprofile.user)
None
django django-models
1个回答
0
投票

同时拥有

CustomUser
Profile
很奇怪。通常,如果您想自定义用户建模,您可以使用所有(可选和必需)数据自己创建一个用户模型,或者如果您不想挂钩自定义
User
模型,则可以使用
 Profile
来存储额外的(通常是可选的)数据,但通常你不会同时执行这两项操作:这通常是两个世界中最糟糕的,因为从那时起你必须实现自定义逻辑来创建和登录用户,但也有通过 ForeignKey
OneToOneField
 查找其他数据。更糟糕的是,这两个模型似乎有 
OneToOneField
 相互链接。通常你会写 
one OneToOneField
,从而反向使用该关系。

我认为在这种特定情况下,最好坚持使用一种模型,从而将字段从

Profile

 移动到 
CustomUser
,并使这些 
blank=True
 
[Django-doc],这使字段可选:

class CustomUser(AbstractBaseUser, PermissionsMixin): username = models.CharField(max_length=150, unique=True) email = models.EmailField(unique=True, null=False) created_at = models.DateTimeField(auto_now_add=True) is_active = models.BooleanField(default=True) is_staff = models.BooleanField(default=False) post_count = models.PositiveIntegerField(default=0) avatar = models.ImageField(upload_to='avatars/', null=True, blank=True) football_club = models.CharField(max_length=100, null=True, blank=True) location = models.CharField(max_length=100, blank=True) USERNAME_FIELD = 'username' REQUIRED_FIELDS = [] objects = CustomUserManager() def __str__(self): return self.username
那么表格就简化为:

from django.contrib.auth.forms import UserCreationForm from django import forms class SignUpForm(UserCreationForm): class Meta: model = CustomUser fields = ['username', 'email', 'avatar', 'football_club', 'location']
并且 

Profile

 只能创建字段的子集:

class ProfileForm(forms.ModelForm): class Meta: model = CustomUser fields = ['avatar', 'football_club', 'location'] @login_required def profile(request): profile = request.user if request.method == 'POST': form = ProfileForm(request.POST, request.FILES, instance=profile) if form.is_valid(): form.save() return redirect('profile') else: form = ProfileForm(instance=profile) return render(request, 'accounts/profile.html', {'form': form})
因此,我们不需要定义 

OneToOneField

 的值,并且绝对不需要双向链接这些值。性能通常也会更好,因为它不需要额外的查询来获取用户的 
.location
.avatar
 等。


注意:Django 的 DateTimeField

 [Django-doc]
有一个 auto_now_add=…
 参数
[Django-doc] 使用时间戳。这将自动分配当前日期时间 创建对象时,将其标记为不可编辑(
editable=False
),例如
默认情况下它不会出现在 
ModelForm
 中。


注意:请不要在模型中存储聚合:在需要时确定聚合:在模型中存储聚合会使更新和保持数据同步变得更加困难。

© www.soinside.com 2019 - 2024. All rights reserved.