在 Django 博客模型中实现保存 draft/publish 功能
implementing save draft/publish feature in django blog model
所以我用 Django 建立了一个非常基本的博客。我一直在努力添加一项新功能,允许我将新的 post 保存为草稿以便稍后发布,或者取消发布已经发布的 post。我是 Django/Python 的新手,所以我可能在这里犯了一个新手错误。
为此,我在 Post 模型中添加了两个字段。一个名为 published 的 BooleanField
和一个名为 publish_date 的 DateTimeField
。我只希望 publish_date 在 publish 设置为 True
且之前为 False
时进行更新。我采用的方法是重写 Post 模型的 save()
方法。在该方法中,我要么将 publish_date 设置为 None
(如果 published 在表单上未选中)或者我我正在将 publish_date 设置为 timezone.now() (如果 published 在表单上被选中)。
这个方法没问题,虽然publish_date每次更新post都会更新,即使没有unpublished/republished .这不可能发生。我仍在学习视图、模型和表单之间的交互,因此非常感谢任何指导。
请查看所有相关代码,让我知道解决此问题的更好方法。感谢您的帮助!
models.py
class Post(models.Model):
title = models.CharField(max_length=255)
body = RichTextUploadingField(blank=True, null=True)
author = models.ForeignKey(User, on_delete=models.CASCADE)
header_image = models.ImageField(upload_to="images/header_images/", default='images/header_images/default.jpg')
slug = models.SlugField(max_length=255, blank=True, null=True)
snippet = models.CharField(max_length=255)
created_date = models.DateTimeField(auto_now_add=True)
updated_date = models.DateTimeField(auto_now=True, blank=False, null=False)
publish_date = models.DateTimeField(auto_now_add=False, blank=True, null=True)
likes = models.ManyToManyField(User, related_name='blog_post', blank=True)
published = models.BooleanField()
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('article-details', kwargs={"pk":self.pk,"slug":self.slug})
def total_likes(self):
return self.likes.count()
def save(self, *args, **kwargs):
if self.published == True:
self.publish_date = timezone.now()
else:
self.publish_date = None
super(FakePost, self).save(*args, **kwargs)
Forms.py
class ArticleNewForm(forms.ModelForm):
class Meta:
model = Post
fields = (
'title',
'slug',
'author',
'header_image',
'body',
'snippet',
'publish_date',
'published',
)
widgets = {
'title': forms.TextInput(),
'author': forms.TextInput(attrs={'class':'form-control', 'value':'','id':'userfield','type':'hidden',}),
'body': forms.Textarea(),
'snippet': forms.Textarea(),
'publish_date': DateTimeInput(attrs={'type': 'datetime-local'}),
}
为避免 publish_date 每次更新 post 时都会更新,即使尚未 unpublished/republished 也应检查如果 self.published 的新值与之前的值发生了变化,如果他这样做了,请执行您的代码。
Django 本身没有给你一个简单的工具来检查值是否已经改变,所以你将不得不使用 this question.
的一些答案
您可以一直避免使用已发布的,并将发布日期设置为“发布”Post。
from django.utils import timezone
from django.utils.functional import cached_propery
class Post(models.Model):
# ...
publish_date = models.DateTimeField(blank=True, null=True, default=None)
@cached_property
def is_published(self):
return self.publish_date <= timezone.now()
def publish(self):
self.publish_date = timezone.now()
检查是否在模板中发布:
{% if post.is_published %}
<span>Published!</span>
{% endif %}
发表一篇post:
post = Post()
post.publish()
post.save()
所有已发布 posts 的查询集:
Post.objects.filter(publish_date__isnull=False).all()
相反,post尚未发布:
Post.objects.filter(publish_date__isnull=True).all()
在查询集中发布所有 post:
Post.objects.update(publish_date=timezone.now())
甚至,您可以实现未来的发布,例如3 天内:
Post.objects.update(publish_date=timezone.now() + timezone.timedelta(days=3))
所以我用 Django 建立了一个非常基本的博客。我一直在努力添加一项新功能,允许我将新的 post 保存为草稿以便稍后发布,或者取消发布已经发布的 post。我是 Django/Python 的新手,所以我可能在这里犯了一个新手错误。
为此,我在 Post 模型中添加了两个字段。一个名为 published 的 BooleanField
和一个名为 publish_date 的 DateTimeField
。我只希望 publish_date 在 publish 设置为 True
且之前为 False
时进行更新。我采用的方法是重写 Post 模型的 save()
方法。在该方法中,我要么将 publish_date 设置为 None
(如果 published 在表单上未选中)或者我我正在将 publish_date 设置为 timezone.now() (如果 published 在表单上被选中)。
这个方法没问题,虽然publish_date每次更新post都会更新,即使没有unpublished/republished .这不可能发生。我仍在学习视图、模型和表单之间的交互,因此非常感谢任何指导。
请查看所有相关代码,让我知道解决此问题的更好方法。感谢您的帮助!
models.py
class Post(models.Model):
title = models.CharField(max_length=255)
body = RichTextUploadingField(blank=True, null=True)
author = models.ForeignKey(User, on_delete=models.CASCADE)
header_image = models.ImageField(upload_to="images/header_images/", default='images/header_images/default.jpg')
slug = models.SlugField(max_length=255, blank=True, null=True)
snippet = models.CharField(max_length=255)
created_date = models.DateTimeField(auto_now_add=True)
updated_date = models.DateTimeField(auto_now=True, blank=False, null=False)
publish_date = models.DateTimeField(auto_now_add=False, blank=True, null=True)
likes = models.ManyToManyField(User, related_name='blog_post', blank=True)
published = models.BooleanField()
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('article-details', kwargs={"pk":self.pk,"slug":self.slug})
def total_likes(self):
return self.likes.count()
def save(self, *args, **kwargs):
if self.published == True:
self.publish_date = timezone.now()
else:
self.publish_date = None
super(FakePost, self).save(*args, **kwargs)
Forms.py
class ArticleNewForm(forms.ModelForm):
class Meta:
model = Post
fields = (
'title',
'slug',
'author',
'header_image',
'body',
'snippet',
'publish_date',
'published',
)
widgets = {
'title': forms.TextInput(),
'author': forms.TextInput(attrs={'class':'form-control', 'value':'','id':'userfield','type':'hidden',}),
'body': forms.Textarea(),
'snippet': forms.Textarea(),
'publish_date': DateTimeInput(attrs={'type': 'datetime-local'}),
}
为避免 publish_date 每次更新 post 时都会更新,即使尚未 unpublished/republished 也应检查如果 self.published 的新值与之前的值发生了变化,如果他这样做了,请执行您的代码。
Django 本身没有给你一个简单的工具来检查值是否已经改变,所以你将不得不使用 this question.
的一些答案您可以一直避免使用已发布的,并将发布日期设置为“发布”Post。
from django.utils import timezone
from django.utils.functional import cached_propery
class Post(models.Model):
# ...
publish_date = models.DateTimeField(blank=True, null=True, default=None)
@cached_property
def is_published(self):
return self.publish_date <= timezone.now()
def publish(self):
self.publish_date = timezone.now()
检查是否在模板中发布:
{% if post.is_published %}
<span>Published!</span>
{% endif %}
发表一篇post:
post = Post()
post.publish()
post.save()
所有已发布 posts 的查询集:
Post.objects.filter(publish_date__isnull=False).all()
相反,post尚未发布:
Post.objects.filter(publish_date__isnull=True).all()
在查询集中发布所有 post:
Post.objects.update(publish_date=timezone.now())
甚至,您可以实现未来的发布,例如3 天内:
Post.objects.update(publish_date=timezone.now() + timezone.timedelta(days=3))