我正在努力学习Django,但我遇到了一些令人困惑的问题.我目前在使用表单创建电影时遇到问题.表单的想法是为用户提供他想要填写的任何字段.用户填写的任何字段都将在其各自的sql表中更新(将忽略空字段).但是,当我提交表单时,表单不断向我提供错误"输入值列表".为了解决这个问题,我认为将表单中的数据填充到列表中,然后返回该列表就可以解决这个问题.
第一个想法是覆盖clean()我的ModelForm.但是,由于表单未能is_valid()在我的视图中进行检查,因此cleaned_data变量in clean()不包含任何内容.接下来,我试图覆盖to_python().但是,to_python()似乎没有被称为.
如果我放入__metaclass__ = models.SubfieldBase相应的模型,我会收到运行时错误
"TypeError:调用元类基类元类冲突时出错:派生类的元类必须是其所有基类的元类的(非严格)子类"
我的方法似乎不起作用.我不确定如何绕过'输入值列表'错误!有什么建议吗?
这是相关代码(更新):
models.py
""" Idea:
A movie consists of many equipments, actors, and lighting techniques. It also has a rank for the particular movie, as well as a title.
A Theater consists of many movies.
A nation consists of many theaters.
"""
from django.db import models
from django.contrib.auth.models import User
class EquipmentModel(models.Model):
equip = models.CharField(max_length=20)
# user = models.ForeignKey(User)
class ActorModel(models.Model):
actor = models.CharField(max_length=20)
# user = models.ForeignKey(User)
class LightModel(models.Model):
light = models.CharField(max_length=20)
# user = models.ForeignKey(User)
class MovieModel(models.Model):
# __metaclass__ = models.SubfieldBase
rank = models.DecimalField(max_digits=5000, decimal_places=3)
title = models.CharField(max_length=20)
equipments = models.ManyToManyField(EquipmentModel, blank=True, null=True)
actors = models.ManyToManyField(ActorModel, blank=True, null=True)
lights = models.ManyToManyField(LightModel, blank=True, null=True)
class TheaterModel(models.Model):
movies = models.ForeignKey(MovieModel)
class NationModel(models.Model):
theaters = models.ForeignKey(TheaterModel)
=====================================
forms.py
"""
These Modelforms tie in the models from models.py
Users will be able to write to any of the fields in MovieModel when creating a movie.
Users may leave any field blank (empty fields should be ignored, ie: no updates to database).
"""
from django import forms
from models import MovieModel
from django.forms.widgets import Textarea
class MovieModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(MovieModelForm, self).__init__(*args, **kwargs)
self.fields["actors"].widget = Textarea()
self.fields["equipments"].widget = Textarea()
self.fields["lights"].widget = Textarea()
def clean_actors(self):
data = self.cleaned_data.get('actors')
print 'cleaning actors'
return [data]
class Meta:
model = MovieModel
=============================================
views.py
""" This will display the form used to create a MovieModel """
from django.shortcuts import render_to_response
from django.template import RequestContext
from forms import MovieModelForm
def add_movie(request):
if request.method == "POST":
form = MovieModelForm(request.POST)
if form.is_valid():
new_moviemodel = form.save()
return HttpResponseRedirect('/data/')
else:
form = MovieModelForm()
return render_to_response('add_movie_form.html', {form:form,}, context_instance=RequestContext(request))
Run Code Online (Sandbox Code Playgroud)
Jos*_*ton 11
可能的问题是文本区域中提供的值列表无法标准化为模型列表.
请参阅ModelMultipleChoiceField文档.
该字段期望有效ID列表,但可能正在接收文本值列表,django无法转换为实际模型实例.在to_python将表单字段内失败,而不是形式本身.因此,价值观甚至都达不到形式.
使用内置的ModelMultipleChoiceField有什么问题吗?它将提供最简单的方法,但需要您的用户扫描可用actor的列表(我在这里使用actors字段作为示例).
在我展示一个如何尝试做你想做的事的例子之前,我必须要问; 你想如何处理数据库中尚不存在的已输入的演员?您可以创建它们(如果存在),也可以失败.你需要对此做出决定.
# only showing the actor example, you can use something like this for other fields too
class MovieModelForm(forms.ModelForm):
actors_list = fields.CharField(required=False, widget=forms.Textarea())
class Meta:
model = MovieModel
exclude = ('actors',)
def clean_actors_list(self):
data = self.cleaned_data
actors_list = data.get('actors_list', None)
if actors_list is not None:
for actor_name in actors_list.split(','):
try:
actor = Actor.objects.get(actor=actor_name)
except Actor.DoesNotExist:
if FAIL_ON_NOT_EXIST: # decide if you want this behaviour or to create it
raise forms.ValidationError('Actor %s does not exist' % actor_name)
else: # create it if it doesnt exist
Actor(actor=actor_name).save()
return actors_list
def save(self, commit=True):
mminstance = super(MovieModelForm, self).save(commit=commit)
actors_list = self.cleaned_data.get('actors_list', None)
if actors_list is not None:
for actor_name in actors_list.split(","):
actor = Actor.objects.get(actor=actor_name)
mminstance.actors.add(actor)
mminstance.save()
return mminstance
Run Code Online (Sandbox Code Playgroud)
以上是所有未经测试的代码,但是如果您真的想要将Textarea用于ModelMultipleChoiceField,那么接近这个代码应该会有效.如果你沿着这条路走下去,并且发现我上面的代码中有错误,请编辑我的答案,或者提供评论,以便我可以.祝好运.
编辑:
另一个选项是创建一个理解逗号分隔的值列表的字段,但其行为方式与ModelMultipleChoiceField类似.查看ModelMultipleChoiceField的源代码,它来自ModelChoiceField,它允许您定义模型上的哪个值用于规范化.
## removed code because it's no longer relevant. See Last Edit ##
Run Code Online (Sandbox Code Playgroud)
编辑:
哇,我真的应该检查django trac,看看这是否已经修复.它是.有关信息,请参阅以下故障单.基本上,他们做了同样的事情.他们让ModelMutipleChoiceField尊重to_field_name参数.这仅适用于django 1.3!
问题是,常规ModelMultipleChoiceField将看到以逗号分隔的字符串,并且因为它不是List或Tuple而失败.因此,我们的工作变得有点困难,因为在常规清理方法可以运行之前,我们必须将字符串更改为列表或元组.
class ModelCommaSeparatedChoiceField(ModelMultipleChoiceField):
widget = Textarea
def clean(self, value):
if value is not None:
value = [item.strip() for item in value.split(",")] # remove padding
return super(ModelCommaSeparatedChoiceField, self).clean(value)
Run Code Online (Sandbox Code Playgroud)
所以,现在你的表单应该是这样的:
class MovieModelForm(forms.ModelForm):
actors = ModelCommaSeparatedChoiceField(
required=False,
queryset=Actor.objects.filter(),
to_field_name='actor')
equipments = ModelCommaSeparatedChoiceField(
required=False,
queryset=Equipment.objects.filter(),
to_field_name='equip')
lights = ModelCommaSeparatedChoiceField(
required=False,
queryset=Light.objects.filter(),
to_field_name='light')
class Meta:
model = MovieModel
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
8915 次 |
| 最近记录: |