Django Celery. Пост Publush на publish_date
У меня есть модель Post. В ней есть поле publish_date
. Если пост имеет статус planned
, то мне нужно выполнить функцию публикации по дате публикации (publish_date). Как я могу это сделать?
models.py:
class Post(models.Model):
STATES = (
('draft', 'Draft'),
('published', 'Published'),
('planned', 'Planned')
)
state = models.CharField(choices=STATES, default=STATES[0][0])
channels = models.ManyToManyField('channel.Channel')
creator = models.ForeignKey('authentication.User', on_delete=models.SET_NULL, null=True)
publish_date = models.DateTimeField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
@receiver(post_save, sender=Post)
def reschedule_publish_task(sender, instance, **kwargs):
# There should be a task setting for a specific time here, as I understand it
Я пытался сделать это, но ничего не вышло, задание не выполнено.
models.py
@receiver(post_save, sender=Post)
def reschedule_publish_task(sender, instance, **kwargs):
task_id = f"publish_post_{instance.id}"
if instance.state == 'planned' and instance.publish_date:
publish_post.apply_async((instance.id,), eta=instance.publish_date, task_id=task_id)
tasks.py
@shared_task
def publish_post(post_id: int) -> None:
from .models import Post
post = Post.objects.filter(id=post_id).first()
if post:
if post.state == 'planned' and post.publish_date <= now():
post.state = 'published'
post.save()
Вы можете попробовать установить модуль django-celery-results
, который поможет вам просматривать журналы Celery из панели администратора.
@shared_task
def publish_post(post_id: int) -> None:
from .models import Post
post = Post.objects.filter(id=post_id).first()
if post:
if post.state == 'planned' and post.publish_date <= now():
post.state = 'published'
post.save()
return JsonResponse({"success": True})
return JsonResponse({"success": False, "error": "date of post Error", "data": f"Post ID: {post_id} \n Post date: {post.publish_date} \n Post state {post.state} \n Date now: {now()}"})
return JsonResponse({"success": False, "error": "Post not found", "data": post_id})
Кроме того, убедитесь, что и рабочий, и ритм запущены.
Я бы посоветовал не работать с задачей для установки статуса. Представьте, что вы позже измените дату публикации, вам нужно будет отменить предыдущую задачу и запланировать новую, что усложнит задачу. Можно даже установить дату публикации в прошлом, и тогда задача может не выполниться.
Вы можете отфильтровать неопубликованные элементы. Действительно, мы можем определить модель следующим образом:
from django.conf import settings
class Post(models.Model):
STATES = (('draft', 'Draft'), ('planned', 'Planned'))
state = models.CharField(choices=STATES, default=STATES[0][0])
channels = models.ManyToManyField('channel.Channel')
creator = models.ForeignKey(
settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True
)
publish_date = models.DateTimeField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
и в ListView
работе с:
from django.db.models.functions import Now
class PostListView(models.Model):
queryset = Post.object.filter(state='planned', publish_date__lte=Now())
Таким образом, если в будущем вы установите publish_date
, Post
автоматически перестанет отображаться.
Note: It is normally better to make use of the
settings.AUTH_USER_MODEL
[Django-doc] to refer to the user model, than to use theUser
model [Django-doc] directly. For more information you can see the referencing theUser
model section of the documentation.