【问题标题】:Django hidden field is not saving to databaseDjango隐藏字段未保存到数据库
【发布时间】:2017-12-11 18:14:21
【问题描述】:

我正在尝试在我的扩展配置文件模型中保存用户 IP 地址。目标是使它成为一个隐藏的领域。目前,我可以通过将 IP 地址打印到控制台来进行调试。当我尝试保存信息时出现问题。

views.py

def index(request):
    #request.session.flush()
    if request.user.is_authenticated:
        return redirect('ve:dashboard')
    elif request.method == 'POST':
        form = RegistrationForm(request.POST)

        if form.is_valid():
            user = form.save(commit=False)
            user.refresh_from_db() # Load the profile instance created by the Signal
            user.profile.birth_date = form.cleaned_data.get('birth_date')
            user.ipaddress = get_ip(request)
            print(user.ipaddress)
            user.save()
            raw_password = form.cleaned_data.get('password1')
            user = authenticate(username=user.username, password=raw_password)
            login(request, user)
            return redirect('ve:dashboard')
    else:
        form = RegistrationForm()
    return render(request, 'index.html', {'form': form})

forms.py

class RegistrationForm(UserCreationForm):
    # birth_date = forms.DateField(help_text='Required. Format: YYYY-MM-DD')
    birth_date = forms.DateField(widget=SelectDateWidget(years=range(1999, 1910, -1)))
    #ipaddress = forms.IntegerField(widget=forms.HiddenInput(), required=False)

    class Meta:
        model = User
        fields = ('username', 'email', 'birth_date', 'password1', 'password2',)
        exclude = ['ipaddress',]

index.html

    <form method="post">
    {% csrf_token %}
    {% for field in form %}
        <p class="text-left">
        {{ field.label_tag }}<br>
        {{ field }}
        {% for error in field.errors %}
          <p style="color: red">{{ error }}</p>
        {% endfor %}
        </p>
    {% endfor %}
    <button type="submit">Sign up</button>
    </form>

models.py

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    ...
    ipaddress = models.CharField(default="0.0.0.0", max_length=30)

在我尝试添加 ipaddress 字段之前,此表单运行良好。我一直在尝试几个版本,有时表单会创建一个新用户,但没有保存 ipaddress..

上面的当前代码在 POST 上给了我错误: DoesNotExist at / 用户匹配查询不存在。由于这一行 "user.refresh_from_db() # 加载 Signal 创建的配置文件实例"

【问题讨论】:

  • 这将保存IP地址;当您执行user.refresh_from_db() 时,表单中的所有其他数据都将被替换。你为什么这样做?
  • 您应该使用GenericIPAddressField,您将受益于开箱即用的验证,并且您可以同时支持 ipv4 和 ipv6 ;)
  • 另请注意,如果您从RegistrationForm 中取消注释ipaddress,它将在您遍历所有字段并呈现它们时呈现在您的html 中。如果您将&lt;form method="post"&gt; 的内容替换为{{ form }},它将正确呈现HiddenInput ;)

标签: python django


【解决方案1】:

来自文档:

这个 save() 方法接受一个可选的 commit 关键字参数,它接受 True 或 False。如果您在 commit=False 的情况下调用 save(),那么它将返回一个尚未保存到数据库的对象。

因此,由于您将提交作为False 传递,因此您将获得一个未保存的实例。尝试在数据库中实际不存在的对象上调用 refresh_from_db 将失败,这显然是在做的。如果模型的实例没有id,那么refresh_from_db 在调用它时将失败。

至于一直无法保存 IP 地址,我注意到您的表单元已将模型设置为 User 对象。默认的 Django User 对象没有 IP 地址。我看到在您链接的模型文件中,您有一个 Profile 模型,它确实有一个 IP 地址,所以在这种情况下,我认为您只是设置了错误的表单。或者您需要以不同的方式处理请求。

形式变化

当前您的表单正在尝试创建/修改 Django User 模型。除非您创建了未显示的自定义 User 模型,否则即使您设置 user.ipaddress = &lt;address&gt; 然后保存用户,此用户模型也不会在数据库中将 ipaddress 作为字段address 不会在当前范围之外持续存在,因为您所做的只是为 user 实例声明一个新变量。

如果您将表单更改为指向您的Profile 模型,您将能够使用profile.ipaddress = &lt;address&gt; 保存地址并成功保存。但是您必须更新您的模板,因为默认情况下它只会显示您的个人资料的字段,而不是与之关联的用户对象。

更改模板/视图

您还可以更改模板和视图以适应它。显然,您的视图能够使用 get_ip 函数生成 IP 地址,因此我暂时假设您的模板没有问题,因此唯一需要更改的是您的视图。

当前,当您的视图调用 form.save 时,它正在获取未保存的 User 实例。这意味着您需要保存用户,然后创建一个 Profile 模型来引用它并附加您的 IP 地址。

def index(request):
    #request.session.flush()
    if request.user.is_authenticated:
        return redirect('ve:dashboard')
    elif request.method == 'POST':
        form = RegistrationForm(request.POST)

        if form.is_valid():
            user = form.save(commit=False)
            # do anything you need to the unsaved user here
            user.save()
            prof = Profile.objects.create(user=user, 
                                          ipaddress=get_ip(request),
                                          date=form.cleaned_data.get('birth_date')
            # no need to save prof since we called objects.create
            raw_password = form.cleaned_data.get('password1')
            user = authenticate(username=user.username, password=raw_password)
            login(request, user)
            return redirect('ve:dashboard')
    else:
        form = RegistrationForm()
    return render(request, 'index.html', {'form': form})

【讨论】:

  • 谢谢,这解决了我收到的当前错误消息,但 ipaddress 字段仍未保存。
  • @AlexWinkler 检查编辑。我可能已经解决了你的问题?
  • 如果我理解你想要做什么,我实际上认为这已经在其他地方解决了。 This 问题也可能涵盖您正在尝试做的事情。
  • 您好,很抱歉耽搁了时间,感谢您迄今为止的所有帮助。我应用了上面的更改,现在一切正常。我改为“user.profile.ipaddress = get_ip(request)”并删除了“commit=False”。唯一剩下的就是隐藏模板中的字段。 Django 表单会打印所有字段。这只会隐藏输入区域,而不是标签“widget=forms.HiddenInput()”,并且“exclude = ['ipaddress',]” 似乎没有任何作用。跨度>
  • 好的,这成功了。 1. 删除ipaddress = forms.IntegerField(required=False) 2. 离开exclude = ('ipaddress',) 3. 保留fields = ('ipaddress',)
猜你喜欢
  • 2018-06-27
  • 1970-01-01
  • 2012-06-08
  • 2020-09-29
  • 2016-10-04
  • 2020-05-23
  • 1970-01-01
  • 1970-01-01
  • 2021-02-24
相关资源
最近更新 更多