1

I have model which has Meta: unique_together = ['slug', 'person'], person is foreign key field. In my form I don't want to type slug field. I want to populate it from child_name field. I tried as:

class ChildForm(SlugCleanMixin, forms.ModelForm):

    class Meta:
        model = Child
        fields = ('child_name','slug','child_birth_date','blood_group')

        def slug(self):
            return slugify(self.child_name)

But slug field not autopopulated from child_name. I also tried using pre_save in models as:

def create_slug(instance, new_slug=None):
    slug = slugify(instance.child_name)
    if new_slug is not None:
        slug = new_slug
    qs = Child.objects.filter(slug=slug).order_by("-id")
    exists = qs.exists()
    if exists:
        new_slug = "%s-%s" %(slug, qs.first().id)
        return create_slug(instance, new_slug=new_slug)
    return slug


def pre_save_post_receiver(sender, instance, *args, **kwargs):
    if not instance.slug:
        instance.slug = create_slug(instance)

pre_save.connect(pre_save_post_receiver, sender=Child)

But nothing fulfill my purpose. How could I do that? Any help will be appreciated.

MY SlugCleanMixin:

class SlugCleanMixin:
    """Mixin class for slug cleaning method."""

    def clean_slug(self):
        new_slug = (
            self.cleaned_data['slug'].lower())
        if new_slug == 'create':
            raise ValidationError(
                'Slug may not be "create".')
        return new_slug

my views:

class ChildrenCreate( ChildrenGetObjectMixin,
    PersonContextMixin, CreateView):
    template_name = 'member/children_form.html'
    model = Child
    form_class = ChildForm


    def get_initial(self):
        person_slug = self.kwargs.get(
            self.person_slug_url_kwarg)
        self.person = get_object_or_404(
            Person, slug__iexact=person_slug)
        initial = {
            self.person_context_object_name:
                self.person,
        }
        initial.update(self.initial)
        return initial

Models:

class Child(models.Model):
    person = models.ForeignKey(Person, on_delete=models.CASCADE)
    child_name = models.CharField(max_length=150)
    slug = models.SlugField(max_length=100)
    child_birth_date = models.DateField()
    blood_group = models.CharField(max_length=5, blank=True)

    objects = ChildrenManager()


    class Meta:
        verbose_name_plural = 'children'
        ordering = ['-child_birth_date']
        unique_together = ['slug', 'person']
dj pro
  • 183
  • 1
  • 3
  • 17

2 Answers2

0

I would try checking out this package for generating slugs, as I've used in several applications, and think it's great:

https://github.com/un33k/django-uuslug

They provide a simple example for usage, which adapting for your models would be:

class Child(models.Model):
    child_name = models.CharField(max_length=150)
    slug = models.SlugField(max_length=100)
    ...

    def save(self, *args, **kwargs):
        self.slug = uuslug(self.child_name, instance=self)
        super(Child, self).save(*args, **kwargs)  
tdsymonds
  • 1,679
  • 1
  • 16
  • 26
  • Sorry, your solution does not restrict duplicate of same parent and same child. It produced same many child. – dj pro Nov 13 '16 at 04:04
0

First of all remove slug from the form fields as you need not take from the user. The form will play no part in this. So your form becomes as below:

class ChildForm(SlugCleanMixin, forms.ModelForm):
    class Meta:
        model = Child
        fields = ('child_name','child_birth_date','blood_group')

Then, in your model override the save function. So, it becomes something like this:

class Child(models.Model):
    person = models.ForeignKey(Person, on_delete=models.CASCADE)
    child_name = models.CharField(max_length=150)
    slug = models.SlugField(max_length=100)
    child_birth_date = models.DateField()
    blood_group = models.CharField(max_length=5, blank=True)

    objects = ChildrenManager()

    def save(self):
        if self._created or 'child_name' in self._get_changed_fields():
            self.slug = create_slug(self)


    class Meta:
        verbose_name_plural = 'children'
        ordering = ['-child_birth_date']
        unique_together = ['slug', 'person']

And you are done. Hope this solves your problem.

Animesh Sharma
  • 3,258
  • 1
  • 17
  • 33
  • Thanks your reply in your save method, there is self.slug = create_slug(self). Which create_slug I will use. Should I use create_slug method which I posted in my question or I use slugify(self.child_name) instead? – dj pro Nov 13 '16 at 03:33
  • 1
    Using the standard slugify method provided by django, there is a chance that your slugs may not remain unique if multiple documents have the same child_name. I guess you have tried adding ids (like 1,2,3 etc) when slugs already exist. Thus, your approach would be better if you plan on filtering the data on the basis if slug. – Animesh Sharma Nov 13 '16 at 06:53
  • I solved this using javascript. I use django admin's urlify.js to auto slugify my slug field with child_name. All other option causes problem of uniqueness. – dj pro Nov 14 '16 at 05:58