如何在表单中正确引用用户模型

How to correctly reference the User model in a form

基本上,我正在尝试为我的网站提供一项功能,让人们可以在他们的用户帐户中注册一个电子小鬼(多个)。我的问题是我的 Device 模型,通过扩展我的 DeviceForm ModelForm 使用 ForeignKey 来引用用户对象。因此,当我去注册一个设备时,它会询问设备的名称、imp 的 agent_id、设备类型和与帐户关联的用户。我认为我的 is_valid() 验证失败的地方在于我如何引用用户模型。我不认为它是用户对象的 "valid" 输入。是否有其他方法可以使用用户的用户名 link 将设备连接到正确的帐户?

Models.py:

class Device(models.Model):
    name = models.CharField(max_length=100)
    agent_id = models.CharField(max_length=100)
    device_type = models.CharField(max_length=100, choices=(
        ("imp", "Electric Imp P3V3"),
    ))
    owner = models.ForeignKey(User)

    def __unicode__(self):
        return self.name

class DeviceForm(ModelForm):
    class Meta:
        model = Device
        fields = ['name', 'agent_id', 'device_type', 'owner']
    def clean_agent_id(self):
        agent_id = self.cleaned_data['agent_id']
        if Device.objects.exclude(pk=self.instance.pk).filter(agent_id=agent_id).exists():
            raise forms.ValidationError(u'agent_id "%s" is already in use.' % agent_id)
        return agent_id

Views.py:

def devices(request):
    devform = DeviceForm(request.POST)
    if devform.is_valid():
        device_obj = devform.save()
        device_obj.save()
        return HttpResponseRedirect('deviceconfirmation')
    else:
        devform = DeviceForm()
    return render_to_response('courses/devices.html', {'devform': devform}, context_instance=RequestContext(request))

devices.html:

{% extends "layout.html" %}
{% load static from staticfiles %}

{% block title %}{{ page.title }}{% endblock %}
{% block content %}
<article>
    <div id="wrapper">
        <p id="devicecreate">Register your device to your account:</p>
        <form action="{% url 'courses:deviceconfirmation' %}" id="devform" method="post"> {% csrf_token %}
            <p>
                <label for="name">Device Name:</label>
                <input id="name" name="name" type="text">
            </p>
            <p>
                <label for="agent_id">Agent ID:</label>
                <input id="agent_id" name="agent_id" type="text">
            </p>
            <p>
                <label for="device_type">Imp Type:</label>
                <select name="device_type" form="devform" id="selectbox">
                    <option value="imp">Imp Regular</option>
                    <option value="Electric Imp P3V3">Imp P3V3</option>
                </select>
            </p>
            <p>
                <label for="owner">Device Owner(username):</label>
                <input id="owner" name="owner" type="text">
            </p>
            <p>
                <input type="submit" value="REGISTER DEVICE" id="submit">
            </p>
        </form>
    </div>

</article>
{% endblock %}

views.py 设备确认:

def deviceconfirmation(request):
    if request.method == 'POST':
        try:
            dev = Device.objects.get(agent_id=request.POST['agent_id'])
            return render(request, 'courses/deviceconfirmation.html', {'dev': dev})
        except Device.DoesNotExist:
            return HttpResponseRedirect('invalidimp')
    else:
        raise Http404('Only POSTs are allowed')

urls.py:

from django.conf.urls import url

from . import views

urlpatterns = [
               url(r'^$', views.homepage, name='homepage'),
               url(r'contact/$', views.contact, name='contact'),
               url(r'login/$', views.login, name='login'),
               url(r'products/$', views.products, name='products'),
               url(r'register/$', views.register, name='register'),
               url(r'register/thanks/$', views.thanks, name='thanks'),
               url(r'register/inuse/$', views.inuse, name='inuse'),
               url(r'login/accountinfo/$', views.accountinfo, name='accountinfo'),
               url(r'devices/$', views.devices, name='devices'),
               url(r'devices/deviceconfirmation/$', views.deviceconfirmation, name='deviceconfirmation'),
               url(r'devices/deviceconfirmation/invalidimp/$', views.invalidimp, name='invalidimp'),
]

当登录用户仅向自己添加设备时:您可以在post时将当前用户作为所有者传递给表单。如果不是 posting,您最初不需要表单中的所有者。在表单中,覆盖保存方法并在保存设备实例之前传递所有者。

--

更新 根据评论:

  • 修改为url用于设备确认和查看; url 现在接受设备 ID。请参阅下面的代码更新
  • 另请参阅模板更新信息

查看(假设 def 设备用于 get 和 post):

def devices(request):
    if request.method == 'POST":
        devform = DeviceForm(request.POST, owner=request.user)
        if devform.is_valid():
            dev = devform.save()
            return HttpResponseRedirect(reverse('deviceconfirmation', kwargs={'device_id': dev.id}))
        else:
            return render_to_response('courses/devices.html', {'devform': devform}, context_instance=RequestContext(request))

    else:
        devform = DeviceForm()
    return render_to_response('courses/devices.html', {'devform': devform}, context_instance=RequestContext(request))

查看设备确认:

def deviceconfirmation(request, device_id=None):
        try:
            dev = Device.objects.get(id=device_id)
            return render(request, 'courses/deviceconfirmation.html', {'dev': dev})
        except Device.DoesNotExist:
            return HttpResponseRedirect('invalidimp')

表格:

class DeviceForm(ModelForm):
    class Meta:
        model = Device
        fields = ['name', 'agent_id', 'device_type']

    def __init__(self, *args, **kwargs):
        owner = kwargs.pop('owner', None)
        super(DeviceForm, self).__init__(*args, **kwargs)
        self.owner = owner;

    def clean_agent_id(self):
        agent_id = self.cleaned_data['agent_id']
        if Device.objects.filter(agent_id=agent_id).exists():
            raise forms.ValidationError(u'agent_id "%s" is already in use.' % agent_id)
        return agent_id

    def save(self, commit=True):
        device = super(DeviceForm, self).save(commit=False)
        device.owner = self.owner
        if commit:
            device.save()
        return device

模板:

  • 删除模板中的表单操作 url -> 当您 post 时,它将转到您执行获取的同一视图(即 devices 视图); <form action="" .....>
  • 删除所有者表单字段 - 显示当前所有者用户名,只需使用 {{request.user.username}}

URL:

url(r'devices/deviceconfirmation/(?P<device_id>\S+)/$', views.deviceconfirmation, name='deviceconfirmation'),