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

时间:2015-08-06 16:10:38

标签: validation django-models django-forms

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

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'),
]

1 个答案:

答案 0 :(得分:1)

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

-

根据评论

更新

  • 修改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))

查看deviceconfirmation:

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

模板:

  • 删除模板中的表单操作网址 - &gt;当你发帖时,它会转到你从中获取get的同一个视图(这是devices视图); <form action="" .....>
  • 删除所有者表单字段 - 显示当前所有者用户名,只需使用 {{request.user.username}}

网址:

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