Tuesday, August 13, 2013

Re: Incrementing the slug by avoiding Integrity error in django models save method

On Mon, Aug 12, 2013 at 9:46 AM, shiva krishna <shivakrshn49@gmail.com> wrote:
> I have a model with two fields as below
>
> **models.py**
>
> class Publisher(models.Model):
> name = models.CharField(max_length=200)
> slug = models.SlugField(max_length=150, unique=True)
>
> def save(self, *args, **kwargs):
> if not self.id and not self.slug:
> slug = slugify(self.name)
> try:
> slug_exits = Publisher.objects.get(slug=slug)
> if slug_exits:
> self.slug = slug + '_1'
> except Publisher.DoesNotExist:
> self.slug = slug
> super(Publisher, self).save(*args, **kwargs)
>
> Here i am creating a slug based on the `name` field as we can see above
>
> So when we try to create a publisher with `name already exists`, the `save`
> method of the model will add the `_1` to the end.
>
> And when we again try to create a new record with same `name`, an
> `Integrity` error will be raised as below
>
> >> Publisher.objects.create(name="abc")
> result: slug will be "abc"
> >> Publisher.objects.create(name="abc")
> result: slug will be "abc_1"
> >> Publisher.objects.create(name="abc")
> result:
>
> .................
> .................
> 34 del cursor
> 35 del connection
> ---> 36 raise errorclass, errorvalue
> 37
> 38 re_numeric_part = re.compile(r"^(\d+)")
>
> IntegrityError: (1062, "Duplicate entry 'abc_1' for key 'slug'")
>
> So what i am want is if the title/slug already exists in the database and if
> slug contains number in it(at the end like abc`_1`), we should increment it
> that number
>
> So what all i want is to `increment the number in the slug` as below if the
> title/slug already exists in the database
>
> abc
> abc_1
> abc_2
> abc_3
>
> So can anyone please let me know how to implement the above logic of
> incrementing the slug ?
>
> Thanks in advance......
>

You can do this naively easy enough:

def save(self, *args, **kwargs):
if not self.id and not self.slug:
slug = base_slug = slugify(self.name)
for idx in range(99):
if idx:
slug = '%s_%d' % (base_slug, idx)
try:
Publisher.objects.get(slug=slug)
except Publisher.DoesNotExist:
break
super(Publisher, self).save(*args, **kwargs)

This is naive for a couple of reasons:

a) To get the slug for the nth item with the same name, you need to do
n database queries
b) It fails for large numbers of n

Personally, I don't think slugs should conflict - if they conflict it
is no longer a good slug name for that resource. I can see the benefit
of article-name-slug-page-1 -> article-name-slug-page-5, but if you
are doing things like that you should include the page number in the
pre-slugged string.

Cheers

Tom

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at http://groups.google.com/group/django-users.
For more options, visit https://groups.google.com/groups/opt_out.

No comments:

Post a Comment