You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django费用追踪应用求助:自动填充用户+页面创建对象失败

问题描述

我开发了一款用户创建账户后可录入费用进行追踪的应用,系统要求填写customer、category、price、month四个字段。我希望customer字段能自动填充登录用户的username,无需用户从所有客户中选择。

但目前遇到问题:用户无法在页面创建对象,仅能通过admin面板创建。在页面创建时会抛出错误:

RelatedObjectDoesNotExist at / User has no customer.

我怀疑该问题与用户是在admin页面“认证与授权”板块下的Users中添加,而非由应用在Customers下创建有关(对象存储在Finance板块中)。

核心需求

  • 实现customer字段自动填充登录用户的username;
  • 修复页面无法创建对象的问题,恢复用户从前可直接在页面创建对象的功能。

相关代码文件

models.py

class Customer(models.Model):
    user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
    name = models.CharField(max_length=200, null=True)
    email = models.CharField(max_length=200, null=True, blank=True)
    date_created = models.DateTimeField(auto_now_add=True, null=True)

    # def __str__(self):
    #     return self.name #I don't now if it's correct


class Finance(models.Model):
    expenses_category = [
        ("Saving", "Saving"),
        ("Food", "Food"),
        ("Bills", "Bills"),
        ("Rent", "Rent"),
        ("Extra", "Extra"),
    ]

    expenses_month = [
        ("January", "January"),
        ("February", "February"),
        ("March", "March"),
        ("April", "April"),
        ("May", "May"),
        ("June", "June"),
        ("July", "July"),
        ("August", "August"),
        ("September", "September"),
        ("October", "October"),
        ("November", "November"),
        ("December", "December"),
    ]

    customer = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
    category = models.CharField(choices=expenses_category, max_length=200)
    price = models.IntegerField()
    month = models.CharField(choices=expenses_month, max_length=200)

views.py

@csrf_exempt
def registerPage(request):
    if request.user.is_authenticated:
        return redirect('home')
    else:
        form = CreateUserForm()
        if request.method == 'POST':
            form = CreateUserForm(request.POST)
            if form.is_valid():
                # form.instance.user = request.user
                user = form.save()
                username = form.cleaned_data.get('username')

                group = Group.objects.get(name='customer')
                user.groups.add(group)

                messages.success(request, 'Account was created for ' + username)

                return redirect('login')

        context = {'form': form}
        return render(request, 'app_finance/register.html', context)


def loginPage(request):
    username = None
    if request.user.is_authenticated:
        username = request.user.customer
        return redirect('home')
    else:
        if request.method == 'POST':
            username = request.POST.get('username')
            password = request.POST.get('password')

            user = authenticate(request, username=username, password=password)

            if user is not None:
                login(request, user)
                return redirect('home')
            else:
                messages.info(request, 'Username or password incorrect.')

        context = {}
        return render(request, 'app_finance/login.html', context)


def logoutUser(request):
    logout(request)
    return redirect('login')


def userPage(request):
    return render(request, 'app_finance/user.html')


@login_required(login_url='login')
def homeView(request):
    # customer = Customer.objects.get(id=pk) (not sure#)
    username = None
    items = Finance.objects.filter(customer_id=request.user.id)
    form = FinanceForm(initial={'customer': User})
    if request.method == 'POST':
        username = request.user.customer
        form = FinanceForm(request.POST)  # initial={'customer': user}
        if form.is_valid():
            form.save()
            return HttpResponseRedirect('/')
    else:
        form = FinanceForm()
        return render(request, 'app_finance/home.html', {'form': form, 'items': items})

forms.py

class CustomerForm(ModelForm):
    class Meta:
        model = Customer
        fields = '__all__'
        exclude = ['user']


class CreateUserForm(UserCreationForm):
    class Meta:
        model = User
        fields = ['username', 'email', 'password1', 'password2']


class FinanceForm(ModelForm):
    class Meta:
        model = Finance
        fields = '__all__'

templates/home.html

<div>
    <span>Hello, {{ request.user }}</span> <br>
    <span><a class="hello-msg" href="{% url 'logout' %}">Logout</a></span>
</div>


<form action="" method="post">
    {% csrf_token %}
    {{ form }}
    <!-- {{ form }} -->

    <input type="submit" value="Submit">
</form>

<br>
<div class="row">
    <div class="col-md">
        <div class="card card-body">
            <h1>Expenses</h1>
        </div>
        <div class="card card-body">
            <table class="table">
                <tr>
                    <th>User</th>
                    <th>Category</th>
                    <th>Price</th>
                    <th>Month</th>
                </tr>
                {% for i in items %}
                    <tr>
                        <td>{{ i.customer }}</td>
                        <td>{{ i.category }}</td>
                        <td>{{ i.price }}</td>
                        <td>{{ i.month }}</td>
                        <td>&nbsp;&nbsp;</td>
                        <td><a class="btn btn-sm btn-info" href="">Update</a></td>
                        <td><a class="btn btn-sm btn-danger" href="">Delete</a></td>
                    </tr>
                {% endfor %}
            </table>
        </div>
    </div>
</div>

修复方案

1. 解决User has no customer错误

错误根源是新注册的User没有关联的Customer对象(一对一关系未建立),需要在用户注册时自动创建Customer:

修改views.py中的registerPage函数:

@csrf_exempt
def registerPage(request):
    if request.user.is_authenticated:
        return redirect('home')
    else:
        form = CreateUserForm()
        if request.method == 'POST':
            form = CreateUserForm(request.POST)
            if form.is_valid():
                user = form.save()
                username = form.cleaned_data.get('username')
                # 自动创建关联的Customer对象
                Customer.objects.create(user=user, name=username, email=form.cleaned_data.get('email'))
                
                group = Group.objects.get(name='customer')
                user.groups.add(group)

                messages.success(request, 'Account was created for ' + username)

                return redirect('login')

        context = {'form': form}
        return render(request, 'app_finance/register.html', context)

2. 实现customer字段自动填充并隐藏

首先修改forms.py的FinanceForm,移除customer字段,避免用户手动选择:

class FinanceForm(ModelForm):
    class Meta:
        model = Finance
        fields = ['category', 'price', 'month']  # 只保留需要用户输入的字段

然后修改views.py的homeView,在保存Finance对象时自动关联当前登录用户:

@login_required(login_url='login')
def homeView(request):
    items = Finance.objects.filter(customer_id=request.user.id)
    if request.method == 'POST':
        form = FinanceForm(request.POST)
        if form.is_valid():
            finance = form.save(commit=False)  # 暂不保存到数据库
            finance.customer = request.user  # 关联当前登录用户
            finance.save()
            return HttpResponseRedirect('/')
    else:
        form = FinanceForm()
    return render(request, 'app_finance/home.html', {'form': form, 'items': items})

3. 修复loginPage中的错误

loginPage中username = request.user.customer会触发关联不存在的错误,直接移除该行:

def loginPage(request):
    if request.user.is_authenticated:
        return redirect('home')
    else:
        if request.method == 'POST':
            username = request.POST.get('username')
            password = request.POST.get('password')

            user = authenticate(request, username=username, password=password)

            if user is not None:
                login(request, user)
                return redirect('home')
            else:
                messages.info(request, 'Username or password incorrect.')

        context = {}
        return render(request, 'app_finance/login.html', context)

4. 完善Customer模型的__str__方法

让Customer对象在admin和页面中显示更友好:

class Customer(models.Model):
    user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
    name = models.CharField(max_length=200, null=True)
    email = models.CharField(max_length=200, null=True, blank=True)
    date_created = models.DateTimeField(auto_now_add=True, null=True)

    def __str__(self):
        return self.name or self.user.username  # 优先显示name,为空则显示用户名

内容的提问来源于stack exchange,提问作者Francisco

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 00:22:06