Populating django field with pre_save()?

前端 未结 5 1178
囚心锁ツ
囚心锁ツ 2020-12-13 05:39
class TodoList(models.Model):
    title = models.CharField(maxlength=100)
    slug = models.SlugField(maxlength=100)
    def save(self):
        self.slug = title
           


        
相关标签:
5条回答
  • 2020-12-13 06:19
    @receiver(pre_save, sender=TodoList)
    def my_callback(sender, instance, *args, **kwargs):
        instance.slug = slugify(instance.title)
    
    0 讨论(0)
  • 2020-12-13 06:22

    Most likely you are referring to django's pre_save signal. You could setup something like this:

    from django.db.models.signals import pre_save
    from django.dispatch import receiver
    from django.template.defaultfilters import slugify
    
    @receiver(pre_save)
    def my_callback(sender, instance, *args, **kwargs):
        instance.slug = slugify(instance.title)
    

    If you dont include the sender argument in the decorator, like @receiver(pre_save, sender=MyModel), the callback will be called for all models.

    You can put the code in any file that is parsed during the execution of your app, models.py is a good place for that.

    0 讨论(0)
  • 2020-12-13 06:31

    you can use django signals.pre_save:

    from django.db.models.signals import post_save, post_delete, pre_save
    
    class TodoList(models.Model):
        @staticmethod
        def pre_save(sender, instance, **kwargs):
            #do anything you want
    
    pre_save.connect(TodoList.pre_save, TodoList, dispatch_uid="sightera.yourpackage.models.TodoList") 
    
    0 讨论(0)
  • 2020-12-13 06:36

    The pre_save() signal hook is indeed a great place to handle slugification for a large number of models. The trick is to know what models need slugs generated, what field should be the basis for the slug value.

    I use a class decorator for this, one that lets me mark models for auto-slug-generation, and what field to base it on:

    from django.db import models
    from django.dispatch import receiver
    from django.utils.text import slugify
    
    def autoslug(fieldname):
        def decorator(model):
            # some sanity checks first
            assert hasattr(model, fieldname), f"Model has no field {fieldname!r}"
            assert hasattr(model, "slug"), "Model is missing a slug field"
    
            @receiver(models.signals.pre_save, sender=model)
            def generate_slug(sender, instance, *args, raw=False, **kwargs):
                if not raw and not instance.slug:
                    source = getattr(instance, fieldname)
                    slug = slugify(source)
                    if slug:  # not all strings result in a slug value
                        instance.slug = slug
            return model
        return decorator
    

    This registers a signal handler for specific models only, and lets you vary the source field with each model decorated:

    @autoslug("name")
    class NamedModel(models.Model):
        name = models.CharField(max_length=100)
        slug = models.SlugField()
    
    @autoslug("title")
    class TitledModel(models.Model):
        title = models.CharField(max_length=255)
        slug = models.SlugField()
    

    Note that no attempt is made to generate a unique slug value. That would require checking for integrity exceptions in a transaction or using a randomised value in the slug from a large enough pool as to make collisions unlikely. Integrity exception checking can only be done in the save() method, not in signal hooks.

    0 讨论(0)
  • 2020-12-13 06:36

    Receiver functions must be like this:

    def my_callback(sender, **kwargs):
        print("Request finished!")
    

    Notice that the function takes a sender argument, along with wildcard keyword arguments (**kwargs); all signal handlers must take these arguments.

    All signals send keyword arguments, and may change those keyword arguments at any time.

    Reference here.

    0 讨论(0)
提交回复
热议问题