我有一个表格,要求一首歌的艺术家,标题和混音。艺术家和标题是必填字段,但Mix不是。如果Artist,Title和Mix不存在,表单应该只保存。如果表单有空的艺术家或标题字段,则应显示"此字段是必填的"提交。我遇到的问题是如果Title字段为空但是Artist已填充,它仍会使用get_or_create创建Artist对象(请参阅下面的### forms.py)。如果表单有效,我如何只创建Artist对象?
###########models.py
class Artist (models.Model):
name = models.CharField(max_length=100)
class Track (models.Model):
artist = models.ForeignKey(Artist, blank=True, null=True, on_delete=models.SET_NULL, verbose_name="Artist")
user = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.SET_NULL, verbose_name="Submitted by", default=1)
title = models.CharField(max_length=100, verbose_name="Title")
mix = models.CharField(max_length=100, blank=True, verbose_name="Mix")
###########views.py
class TrackCreateView(SuccessMessageMixin, AjaxCreateView):
form_class = ProfileForm
success_message = "Thank you for submitting track: %(artist)s - %(title)s - %(mix)s"
def get_initial(self):
self.initial.update({ 'user': self.request.user })
return self.initial
def get_success_message(self, cleaned_data):
return self.success_message % dict(cleaned_data,
artist=self.object.artist,
title=self.object.title,
)
###########forms.py
class ProfileForm(forms.ModelForm):
class Meta:
model = Track
fields = [
"artist",
"title",
"mix",
]
artist = forms.CharField(widget=forms.TextInput(attrs={'maxlength': '100',}))
def __init__(self, *args, **kwargs):
self.user = kwargs['initial']['user']
super(ProfileForm, self).__init__(*args, **kwargs)
# Set layout for fields.
my_field_text= [
('artist', 'Artist', ''),
('title', 'Title', ''),
('mix', 'Mix', ''),
]
for x in my_field_text:
self.fields[x[0]].label=x[1]
self.fields[x[0]].help_text=x[2]
self.helper = FormHelper()
self.helper.layout = Layout(
Div(
Div('artist', css_class="col-sm-4"),
Div('title', css_class="col-sm-4"),
Div('mix', css_class="col-sm-4"),
css_class = 'row'
),
)
def save(self, commit=True):
obj = super(ProfileForm, self).save(False)
obj.user = self.user
commit and obj.save()
return obj
def clean(self):
cleaned_data = super(ProfileForm, self).clean()
artist = self.cleaned_data.get('artist')
title = self.cleaned_data.get('title')
mix = self.cleaned_data.get('mix')
if artist and title:
title = ' '.join([w.title() if w.islower() else w for w in title.split()])
if mix:
mix = ' '.join([w.title() if w.islower() else w for w in mix.split()])
if Track.objects.filter(artist=artist, title=title, mix=mix).exists():
msg = "Record with Artist and Title already exists."
if mix:
msg = "Record with Artist, Title & Mix already exists."
self.add_error('mix', msg)
self.add_error('artist', msg)
self.add_error('title', msg)
if not artist:
raise forms.ValidationError("Artist is a required field.")
else:
artist, created = Artist.objects.get_or_create(name=artist)
self.cleaned_data['artist'] = artist
self.cleaned_data['title'] = title
self.cleaned_data['mix'] = mix
return self.cleaned_data
答案 0 :(得分:1)
如何更改比较,首先检查您的表单在clean()
?
def clean(self):
...
if not artist:
raise ValidationError("artist is a required field")
if not title:
raise ValidationError("title is a required field")
...
以上为用户提供了两个步骤,因为如果用户将艺术家和标题都留空,他们就会得到艺术家的注意。
你可以创建一个更好的(sub)if语句和一个组合ValidationError
,或者使用clean_artist
和clean_title
解决这个问题,只是为了提升ValidationError
(不使用get_or_create)现场清洁方法):
def clean_artist(self):
# no get_or_create here
...
if not artist:
raise ValidationError("artist is a required field")
def clean_title(self):
# no get_or_create here
...
if not title:
raise ValidationError("title is a required field")
def clean(self):
...
if title and artist:
# get_or_create stuff here
...
这样,你应该独立地得到两个错误,但是只有当标题和艺术家有效时,get_or_create仍然在主干净中完成。