2016-10-08 2 views
0

У меня есть форма, которая запрашивает Исполнитель, Название и Микс песни. Исполнитель и название обязательны для заполнения, но Mix нет. Форма должна сохраняться только при отсутствии Artist, Title и Mix. Если в форме есть пустое поле Artist или Title, оно должно показать «Это поле обязательно» для отправки. Проблема, с которой я сталкиваюсь, заключается в том, что если поле Title пустое, но Artist заполнено, он все равно будет создавать объект Artist с get_or_create (см. ### forms.py ниже). Как создать объект Artist только в том случае, если форма действительна?Django get_or_create только при соблюдении ограничений формы

###########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

Почему у вас есть 'get_or_create (name = artist)' в 'clean_artist', а не в общем' clean'; только в последнем вы можете (как и вы) проверить на 'if artist и title'. – Evert

+0

Я удалил clean_artist и теперь получил его в общем чистом виде. В любом случае, только get_or_create, если форма действительна? – bayman

ответ

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") 
    ... 

выше делает это двухэтапный процесс для пользователя, так как, если пользователь покидает оба исполнитель и название пустого, они ONY получить художник уведомление. Вы могли бы сделать лучше (суб), если заявление и комбинированный 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 все еще выполняется в основном чистом, только если заголовок и исполнитель действительны.