【问题标题】:Triyng to slugify url from title posts in a Django blog试图从 Django 博客中的标题帖子中删除 url
【发布时间】:2021-01-26 02:46:25
【问题描述】:

为期货网址创建了 slug 变量并进行了 ./makemigrations 和 migrate 并且该参数出现在管理面板中,但是当我在进行空的“theblog”迁移后尝试迁移时出现此错误:

class Migration(migrations.Migration):                                                                                                                                                                                                                                              
  File "xxx/theblog/models.py", line 104, in Migration                                                                                                                                                                                            
    migrations.RunPython(generate_slugs_for_old_posts, reverse=reverse_func),                                                                                                                                                                                                           
TypeError: __init__() got an unexpected keyword argument 'reverse'

将 slug 参数从 null 和空白更改为唯一,但现在这似乎不是问题。我知道问题来自 get_success_url 但真的不知道如何解决。

models.py:

from django.utils.text import slugify
        
class Post(models.Model):
        title= models.CharField(max_length=100)
        header_image = models.ImageField(null=True , blank=True, upload_to="images/")
        title_tag= models.CharField(max_length=100)
        author= models.ForeignKey(User, on_delete=models.CASCADE)
        body = RichTextUploadingField(extra_plugins=
        ['youtube', 'codesnippet'], external_plugin_resources= [('youtube','/static/ckeditor/youtube/','plugin.js'), ('codesnippet','/static/ckeditor/codesnippet/','plugin.js')])
        post_date = models.DateTimeField(auto_now_add=True)
        category = models.CharField(max_length=50, default='uncategorized')
        slug = models.SlugField(unique=True)
        snippet = models.CharField(max_length=200)
        status = models.IntegerField(choices=STATUS, default=0)
        likes = models.ManyToManyField(User, blank=True, related_name='blog_posts')
    
        def save(self, *args, **kwargs):
            self.slug = self.generate_slug()
            return super().save(*args, **kwargs)
    
        def generate_slug(self, save_to_obj=False, add_random_suffix=True):
    
            generated_slug = slugify(self.title)
    
            random_suffix = ""
            if add_random_suffix:
                random_suffix = ''.join([
                    random.choice(string.ascii_letters + string.digits)
                    for i in range(5)
                ])
                generated_slug += '-%s' % random_suffix
    
            if save_to_obj:
                self.slug = generated_slug
                self.save(update_fields=['slug'])
    
            return generated_slug

def generate_slugs_for_old_posts(apps, schema_editor):
        Post = apps.get_model("theblog", "Post")
    
        for post in Post.objects.all():
            post.slug = slugify(post.title)
            post.save(update_fields=['slug'])
    
    
def reverse_func(apps, schema_editor):
        pass  # just pass
    
class Migration(migrations.Migration):
        dependencies = []
        operations = [
            migrations.RunPython(generate_slugs_for_old_posts, reverse=reverse_func),
        ]

【问题讨论】:

    标签: django django-urls django-migrations


    【解决方案1】:

    首先,您必须将可为空的 slug 字段添加到您的 Post 模型中。这是 slug 字段上的Django docs。您也必须实现生成 slug 值的方法。您可以在模型上实现generate_slug(...) 方法,例如:

    import string  # for string constants
    import random  # for generating random strings
    
    # other imports ...
    from django.utils.text import slugify
    # other imports ... 
    
    class Post(models.Model):
        # ...
        slug = models.SlugField(null=True, blank=True, unique=True)
        # ...
    
        def save(self, *args, **kwargs):
            self.slug = self.generate_slug()
            return super().save(*args, **kwargs)
    
        def generate_slug(self, save_to_obj=False, add_random_suffix=True):
            """
            Generates and returns slug for this obj.
            If `save_to_obj` is True, then saves to current obj.
            Warning: setting `save_to_obj` to True
                  when called from `.save()` method
                  can lead to recursion error!
    
            `add_random_suffix ` is to make sure that slug field has unique value.
            """
    
            # We rely on django's slugify function here. But if
            # it is not sufficient for you needs, you can implement
            # you own way of generating slugs.
            generated_slug = slugify(self.title)
    
            # Generate random suffix here.
            random_suffix = ""
            if add_random_suffix:
                random_suffix = ''.join([
                    random.choice(string.ascii_letters + string.digits)
                    for i in range(5)
                ])
                generated_slug += '-%s' % random_suffix
    
            if save_to_obj:
                self.slug = generated_slug
                self.save(update_fields=['slug'])
            
            return generated_slug
    

    现在在每个对象保存时,您将自动为您的对象生成 slug。 处理没有设置slug 字段的旧帖子。您必须使用 RunPython (Django docs) 创建自定义迁移:

    首先运行这个命令

    python manage.py makemigrations <APP_NAME> --empty
    

    替换为 Post 模型所在的实际应用名称。 它将生成一个空的迁移文件:

    from django.utils.text import slugify
    from django.db import migrations
    
    def generate_slugs_for_old_posts(apps, schema_editor):
        Post = apps.get_model("<APP_NAME>", "Post")  # replace <APP_NAME> with actual app name
    
        # dummy way
        for post in Post.objects.all():
            # Do not try to use `generate_slug` method
            # here, you probably will get error saying
            # that Post does not have method called `generate_slug`
            # as it is not the actual class you have defined in your
            # models.py!
            post.slug = slugify(post.title)
            post.save(update_fields=['slug'])
    
        
    
    def reverse_func(apps, schema_editor):
        pass  # just pass
    
    class Migration(migrations.Migration):
    
        dependencies = []
    
        operations = [
            migrations.RunPython(generate_slugs_for_old_posts, reverse=reverse_func),
        ]
    

    在那之后,您可以更改 slug 字段并使其不可为空:

    class Post(models.Model):
        # ...
        slug = models.SlugField(unique=True)
        # ... 
    

    现在python manage.py migrate,这将使 slug 字段在以后的帖子中不可为空,但它可能会给你一个警告,说你正在尝试制作现有的列 不可为空。在这里,您可以选择“我已创建自定义迁移”或类似的内容。选择它。

    现在,当您的帖子有 slug 时,您必须修复您的视图,以便它们接受来自 url 的 slug 参数。这里的诀窍是确保您的帖子也被 ID 接受。因为有人可能已经有了指向某些带有 ID 的帖子的链接。如果您删除带有 ID 参数的 URL,那么某人可能无法再使用该旧链接。

    【讨论】:

    • 看起来很容易理解,但我没有得到正确的顺序,我自己不是程序员。我收到错误。我必须使用 generate_slug 函数进行一次空迁移,然后将其替换为 old_posts 和所有内容的迁移?
    • 您遇到了哪些错误?你能更新你的问题吗,你做了什么?
    • 没关系。如果您认为我的回答对您有所帮助,您也可以将其标记为已接受。
    【解决方案2】:

    您也可以将旧网址重定向到新网址

    urls.py

    [..]
    
    from django.views.generic.base import RedirectView
    
    urlpatterns = [
    
        # Redirect old links:
        path('article/<int:pk>', RedirectView.as_view(url='article/<slug:url>', permanent=True)),
    
        # You won't need this path any more
        # path('article/<int:pk>', ArticleDetailView.as_view(), name="article-detail"),
        
        # The new path with slug
        path('article/<slug:url>', ArticleDetailView.as_view(), name="article-detail"),
    
        [..]
    
    ]
    

    参考https://docs.djangoproject.com/en/3.1/ref/class-based-views/base/#redirectview

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多