user9650228
user9650228

Reputation:

Django: Preventing form from being saved inside models.py

I'm working on a Django app in which users can ask a Question, but problem is that in case a user types ???, %%, etc in the question form & submit it, then slug becomes '' (slug == '') & the form gets saved into database.

class Question(models.Model):
    question_text = models.CharField(max_length=250)
    slug = models.SlugField(max_length=255, unique=True)

    def get_unique_slug(self):
        slug = slugify(self.question_text)
        unique_slug = slug
        num = 1
        while Question.objects.filter(slug=unique_slug).exists():
            unique_slug = '{}-{}'.format(slug, num)
            num += 1
        if slug == '':

            # what can we do now?

        return unique_slug

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = self.get_unique_slug()
        return super(Question, self).save()

We have to either prevent slug from being a empty string or simply prevent the form from being saved. How can we do that?

Thank You!

Upvotes: 1

Views: 88

Answers (2)

Lemayzeur
Lemayzeur

Reputation: 8525

In case you want to save something rather than an empty string, this will do the trick.

from django.template.defaultfilters import slugify
import random
import string

def get_unique_slug(instance,new_slug=None,field="question_text"):
    ''' If you want to target another field, you can change the parameter.
    By default we target the "question_text" field '''

    def generator(size=10,chars=string.ascii_letters + string.digits):
        return ''.join(random.choice(chars) for _ in range(size))
    if new_slug:
        slug = new_slug
    else:
        slug = slugify(eval("instance.%s" % field))  # we use `eval` to have the field. 
        if not slug:
            slug = "question{}".format(generator(4))

    Klass = instance.__class__
    qs_exists = Klass.objects.filter(slug=slug).exists()

    if qs_exists:
        new_slug = "%s-%s" % (slug,generator(4))
        return create_slug(instance,new_slug,field)
    return slug

This is you class model. I do not put the 'get_unique_slug' inside the class, in order for you to use it anywhere for other models

class Question(models.Model):
    question_text = models.CharField(max_length=250)
    slug = models.SlugField(max_length=255, unique=True)

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = get_unique_slug(self,field="question_text") # We target the 'question_text' field, although we can let it empty as it's the default value
        return super(Question, self).save()

Upvotes: 0

Alasdair
Alasdair

Reputation: 308799

You could move get_unique_slug into the model's clean method. That way the slug will be validated before the instance is saved.

def clean():
    if not self.slug:
        self.slug = self.get_unique_slug()
    if self.slug == '':
        raise forms.ValidationError("Invalid slug")

Upvotes: 1

Related Questions