#django #django-class-based-views
Вопрос:
Я пытаюсь создать подобную страницу, где цитаты выбираются случайным образом из quotes.models.Цитата с использованием метода классов Quote.get_random()
:
Quote1... by Author1
Quote2... by Author2
RichTextfield for user to comment on the quotes.
Пользователь не должен иметь возможности редактировать цитаты на этой странице, только комментарий. Но я хочу, чтобы связь между цитатами и комментарием пользователя была сохранена.
Я просмотрел предыдущие вопросы и ответы, но они были предназначены для использования нескольких форм в представлении, и пользователь может редактировать все поля. Я также посмотрел на посылку https://django-extra-views.readthedocs.io/en/latest/index.html но я не думаю, что это помогает моей проблеме.
Я застрял на отображении котировок и передаче выбранных котировок в форму для сохранения. Может ли кто-нибудь помочь или подсказать, как я могу добиться прогресса?
Использование {% get_quotes %}
в post.html шаблон, я получаю список словаря для цитат (как показано на скриншоте). {% get_quotes 3 %}
также работает для генерации 3 котировок.
[{'id': 81, 'text': '..., 'tags': [76, 77]}, {'id': 75, 'text': ..., 'tags': [74, 75, 76, 77, 78, 79, 80, 81]}]
Но ничего не происходит, когда я пытаюсь просмотреть список.
{% for quote in get_quotes %}
{{ quote }}
{% endfor %}
quotes.models.py
from django.conf import settings
from django.contrib.auth import get_user_model
from django.db import models
from modelcluster.fields import ParentalKey
from modelcluster.models import ClusterableModel
from modelcluster.contrib.taggit import ClusterTaggableManager
from taggit.models import TagBase, ItemBase
from wagtail.snippets.models import register_snippet
from ckeditor.fields import RichTextField
from itertools import chain
import sys
sys.path.append("..") # Adds higher directory to python modules path.
def to_dict(instance):
opts = instance._meta
data = {}
for f in chain(opts.concrete_fields, opts.private_fields):
data[f.name] = f.value_from_object(instance)
for f in opts.many_to_many:
data[f.name] = [i.id for i in f.value_from_object(instance)]
return data
class Quote(ClusterableModel):
text = RichTextField(
config_name="awesome_ckeditor", help_text="You must enter some quote content"
)
author = models.CharField(
max_length=300, blank=True, help_text="Person who said/wrote this quote"
)
#snipped
@classmethod
def get_random(cls, n=2):
"""Returns a number of random quotes."""
import random
n = int(n) # Number of quotes to return. Default n=2
last = cls.objects.count() - 1
selection = random.sample(range(0, last), n)
random_quotes = []
for each in selection:
pk = cls.objects.filter(active=True)[each].pk
random_quotes.append(to_dict(cls.objects.get(pk=pk)))
return random_quotes
def __str__(self):
"""String repr of this class."""
return f"{self.text} - {self.author}"
class Meta:
verbose_name = "Quote"
verbose_name_plural = "Quotes"
ordering = ("author", "text")
create.models.py
from userauth.models import CustomUser
class UserPost(models.Model):
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
publish = models.DateField(
default=timezone.now,
validators=[
MinValueValidator(
timezone.now().date(), message="The date cannot be in the past!"
)
],
)
created = models.DateTimeField(auto_now_add=True, editable=False)
updated = models.DateTimeField(auto_now=True, editable=False)
STATUS_CHOICES = (
("draft", "Draft"),
("published", "Published"),
)
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default="draft")
active = models.BooleanField(
default=True, help_text="Allows moderator to unpublish posts if set to false"
) # Allows moderators to hide offensive posts
inactive_message = models.TextField(
max_length=500,
blank=True,
help_text="Enter the reason for setting this post to inactive",
)
title = models.CharField(
max_length=300, unique_for_date="publish", help_text="You must enter a title"
)
slug = models.SlugField(max_length=350, unique_for_date="publish")
content = RichTextField(
config_name="awesome_ckeditor", help_text="You must enter some content"
)
quotes = ParentalManyToManyField("quotes.Quote", related_name="user_posts")
def save(self, *args, **kwargs):
if not self.id:
# Newly created object, so set slug
self.slug = slugify(self.title)
return super(UserPost, self).save(*args, **kwargs)
def get_absolute_url(self):
return reverse(
"create:detail",
kwargs={
"year": self.publish.year,
"month": self.publish.month,
"day": self.publish.day,
"slug": self.slug,
},
)
templatetags.create_tags.py
from django import template
from quotes.models import Quote
register = template.Library()
@register.simple_tag
def get_quotes(n=2):
return Quote.get_random(n)
views.py
from .models import UserPost
class OwnerMixin(object):
"""Returns only user's objects to prevent others from accessing."""
def get_queryset(self):
qs = super().get_queryset()
return qs.filter(user=self.request.user)
class OwnerEditMixin(object):
"""Sets user pk"""
def form_valid(self, form):
form.instance.user = self.request.user
return super().form_valid(form)
def get_success_url(self):
return reverse_lazy(
"create:user_post_detail",
kwargs={
"year": self.object.publish.year,
"month": self.object.publish.month,
"day": self.object.publish.day,
"slug": self.object.slug,
},
)
class UserPostCreateView(LoginRequiredMixin, OwnerEditMixin, CreateView):
model = UserPost
fields = ["publish", "status", "title", "content"]
template_name = "create/post.html"
def get_form(self):
form = super().get_form()
form.fields["publish"].widget = DateInput(attrs={"type": "date"})
return form