2

I'm trying to run a validation where a user can't enter the same name_field twice but other users entering the same name will not interfere. I tried using "unique_together = (("username","name_field"))" but when a user enters the same value twice the server generates an integrity error as opposed to rendering a warning message next to the form field.

then I tried overriding the clean() method in my model, Which runs fine if I only check "field_name" like so:

def clean(self):
    existing = self.__class__.objects.filter(
                            name_field=self.name_field).count()
    if existing > 0:
        raise ValidationError({'name_field':self.username })

But I am running into trouble when checking the username value, for instance:

def clean(self):
    existing = self.__class__.objects.filter(
                            username=self.username,  ###This part crashes!!! (username not found)
                            name_field=self.name_field).count()
    if existing > 0:
        raise ValidationError({'name_field':self.username })

I'm guessing due to it not being an actual field in the form its not present during the call to clean(). So my question is am I doing the validation correctly for this kind of problem? And how can I pass or where can I find the value for the current user from within a models clean method (in a safe way hopefully without adding fields to my form)?

views.py

def add_stuff(request):
    if request.user.is_authenticated():
        form = addStuff(request.POST or None)
        if request.method == 'POST':
            if form.is_valid():
                sub_form = form.save(commit=False)
                sub_form.username = request.user
                sub_form.save()
                return redirect('../somewhere_else/')

forms.py

class addStuff(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super(addStuff, self).__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.form_tag = False
        self.helper.layout = Layout(
                                'name_field',
                                'type_field',
                       ButtonHolder(
                                Submit('Save', 'Save')
                                   ),
        )

    class Meta:
        model = UserStuff
        fields = ('name_field',
                  'type_field',
                 )

models.py

class UserStuff(models.Model):
    username                         = models.ForeignKey(User)
    name_field                       = models.CharField(max_length=24, blank=False,null=False)
    type_field                       = models.CharField(max_length=24, blank=True,null=True)

    def clean(self):
        existing = self.__class__.objects.filter(
                                username=self.username,  ###This part crashes!!! (username not found)
                                name_field=self.name_field).count()
        if existing > 0:
            raise ValidationError({'name_field':self.username })

    def __unicode__(self):
        return "%s For User: \"%s\" " % (self.name_field, self.username)

    class Meta:
        managed = True
        db_table = 'my_db_table'
        unique_together = (("username","name_field"))

Thanks for any insight!

Logic1
  • 1,806
  • 3
  • 26
  • 43
  • You should show exactly what you mean by "crashes". What error do you get? What is the traceback? Also, I don't really know why you have put that clean method on the model, rather than the form. – Daniel Roseman Dec 09 '14 at 09:15

1 Answers1

0

I now am running the clean override from the form instead of the model (as recommended by Daniel). This has solved a bunch of issues and I now have a working concept:

models.py

class UserStuff(models.Model):
    username                         = models.ForeignKey(User)
    name_field                       = models.CharField(max_length=24, blank=False,null=False)
    type_field                       = models.CharField(max_length=24, blank=True,null=True)

    def clean(self):
        existing = self.__class__.objects.filter(
                                username=self.username,  ###This part crashes!!! (username not found)
                                name_field=self.name_field).count()
        if existing > 0:
            raise ValidationError({'name_field':self.username })

    def __unicode__(self):
        return "%s For User: \"%s\" " % (self.name_field, self.username)

    class Meta:
        managed = True
        db_table = 'my_db_table'

forms.py

class addStuff(forms.ModelForm):  
    def __init__(self, *args, **kwargs):
        super(addStuff, self).__init__(*args, **kwargs)
        initial = kwargs.pop('initial')
        self.username = initial['user']
        self.helper = FormHelper()
        self.helper.form_tag = False
        self.helper.layout = Layout(
                                'name_field',
                                'type_field',
                       ButtonHolder(
                                Submit('Save', 'Save')
                                   ),
        )
    def clean(self):
        cleaned_data = super(addStuff, self).clean()
        name_field = self.cleaned_data['name_field']
        obj = UserStuff.objects.filter(username_id=self.username.id,
                                       name_field=name_field,
                                      )
        if len(obj) > 0:
            raise ValidationError({'name_field': 
                  "This name already exists!" }  ) 
        return cleaned_data
    class Meta:
        model = UserStuff
        fields = ('name_field',
                  'type_field',
                 )

views.py

def add_stuff(request):
    if request.user.is_authenticated():
        form = addStuff(request.POST or None,
                        initial={'user':request.user})
        if request.method == 'POST':
            if form.is_valid():
                sub_form = form.save(commit=False)
                sub_form.username = request.user
                sub_form.save()
                return redirect('../somewhere_else/')

best of luck!

Logic1
  • 1,806
  • 3
  • 26
  • 43