Django 循环导入(模型-视图(-表单))

问题描述 投票:0回答:1

观看了之前所有专门讨论此问题的相关主题,但尚未找到合适的解决方案,因此决定创建我自己的问题。

我正在创建一个论坛项目(作为网站项目的一部分)。视图是通过基于类的视图创建的:SubForumListView 引导至主论坛页面,其中列出了其主要部分(“子论坛”)。 TopicListView 又引导至某些子论坛的页面,其中包含子论坛内创建的活动主题列表。 ShowTopic 视图会引导至带有评论列表的特定主题页面。

问题的出现是因为:

  1. Models.py:模型
    get_absolute_url
    中的方法
    Subforum
    ,其返回部分的
    reverse
    函数将视图作为第一个参数;我试图避免直接导入视图,但该程序不接受其他变体;
  2. Views.py:大多数视图都在实例参数(
    model = Subforum
    )或使用查询集的方法中导入了模型(如
    get_context_data
    topics = Topic.objects.all()
    );我不能肯定地说实例参数
    model = Subforum
    更改为
    model = 'Subforum'
    是否真的有帮助,因为不可能使用查询集方法来做到这一点,因此无法证明;
  3. Forms.py:我的表单类是通过
    forms.ModelForm
    创建的,并包含
    class Meta
    ,其中
    model
    实例参数的提供方式与 2) 中的相同:
    model = Topic
    。现在我已经评论了它们(再次,不确定它是否有帮助)以及模型的导入,但是当它们处于活动状态时,有一个三重循环导入“模型-视图-表单”(有趣够了)。

我看到了这个问题,我知道是什么以及在哪里引发了它,但我不知道如何解决它,也就是说:我不知道如何更好地定义视图和表单(或者,也许,具有“get_absolute_url”的模型”方法)避免 CI 以及如何更好地组织程序不同部分之间的连接。

对应文件:

models.py:

from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse
from django.utils.text import slugify

from .consts import *
from .views import TopicListView, ShowTopic

'''
class User(AbstractUser):
    class Meta:
        app_label = 'forum'
'''


class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    surname = models.CharField(max_length=32, default='')
    name = models.CharField(max_length=32, default='')
    email = models.EmailField(max_length=254, blank=True, unique=True)
    bio = models.TextField(max_length=500, default="Write a couple of words about yourself")
    avatar = models.ImageField(default=None, blank=True, max_length=255)
    status = models.CharField(max_length=25, blank=True, default='')
    slug = models.SlugField()
    age = models.IntegerField(verbose_name='Возраст', null=True, blank=True)
    gender = models.CharField(verbose_name='Пол', max_length=32, choices=Genders.GENDER_CHOICES, default="H", blank=True)
    reputation = models.IntegerField(verbose_name='Репутация', default=0)

    def __str__(self):
        return f'{self.user} profile'

    def get_absolute_url(self):
        return reverse('user_profile', kwargs={'profile_slug': self.slug})

    def save(self, *args, **kwargs):
        if not self.id:
            self.slug = slugify(self.user.username)
            return super(Profile, self).save(*args, **kwargs)


class Subforum(models.Model):
    title = models.CharField(verbose_name='Название', max_length=32, choices=Theme.THEME_CHOICES, default=1)
    slug = models.SlugField(default='News')
    objects = models.Manager()

    class Meta:
        ordering = ['title']
        verbose_name = 'Разделы форума'
        verbose_name_plural = 'Разделы форума'

    def __str__(self):
        return self.title

    def save(self, *args, **kwargs):
        if not self.id:
            self.slug = slugify(self.title)
            return super(Subforum, self).save(*args, **kwargs)

    def get_absolute_url(self):
        return reverse(TopicListView, kwargs={'name': self.title, 'subforum_slug': self.slug})


class Topic(models.Model):
    subject = models.CharField(verbose_name='Заголовок', max_length=255, unique=True)
    first_comment = models.TextField(verbose_name='Сообщение', max_length=2000, default='')
    slug = models.SlugField(default='', unique=True, max_length=25, editable=False)
    subforum = models.ForeignKey('Subforum',
                                 verbose_name='Раздел',
                                 on_delete=models.CASCADE,
                                 related_name='subforum')
    creator = models.ForeignKey(User,
                                verbose_name='Создатель темы',
                                on_delete=models.SET('deleted'),
                                related_name='creator')
    created = models.DateTimeField(auto_now_add=True)
    closed = models.BooleanField(default=False)
    objects = models.Manager()

    class Meta:
        ordering = ['id']
        verbose_name = 'Обсуждения'
        verbose_name_plural = 'Обсуждения'

    def __str__(self):
        return self.subject

    def save(self, *args, **kwargs):
        if not self.id:
            self.slug = f'topic-{slugify(self.subject)}'[0:25]
            return super(Topic, self).save(*args, **kwargs)

    def get_absolute_url(self):
        return reverse(ShowTopic, kwargs={'topic_slug': self.slug})


class Comment(models.Model):
    topic = models.ForeignKey('Topic',
                              verbose_name='Тема',
                              on_delete=models.CASCADE,
                              related_name='topic')
    author = models.ForeignKey(User,
                               verbose_name='Комментатор',
                               on_delete=models.SET('deleted'),
                               related_name='author')
    content = models.TextField(verbose_name='Текст', max_length=2000)
    created = models.DateTimeField(verbose_name='Дата публикации', auto_now_add=True)
    updated = models.DateTimeField(verbose_name='Дата изменения', auto_now=True)
    objects = models.Manager()

    class Meta:
        ordering = ['created']
        verbose_name = 'Комментарии'
        verbose_name_plural = 'Комментарии'

    def __str__(self):
        return f'Post of {self.topic.subject} is posted by {self.author.username}.'

views.py:

from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import get_object_or_404
from django.urls import reverse_lazy
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView

from core.views import menu
from .forms import AddTopicForm, AddCommentForm
from .models import Subforum, Topic, Comment, Profile
from .utils import DataMixin


class SubForumListView(ListView):
    model = Subforum
    context_object_name = 'subforum_list'
    template_name = "forum/forum.html"

    def get_context_data(self, **kwargs):
        subforums = Subforum.objects.all()
        context = {'subforums': subforums}
        return context


class TopicListView(ListView):
    model = Topic
    template_name = "forum/subforum.html"
    slug_url_kwarg = 'subforum_slug'
    context_object_name = 'subforum'

    def get_context_data(self, **kwargs):
        topics = Topic.objects.all()
        context = {'topics': topics}
        return context


class ShowTopic(DetailView):
    model = Topic
    template_name = "forum/topic.html"
    slug_url_kwarg = 'topic_slug'
    context_object_name = 'topic'

    def get_context_data(self, topic_slug, **kwargs):
        topic = get_object_or_404(Topic, slug=topic_slug)
        comments = Comment.objects.filter(topic=topic)
        comments_number = len(Comment.objects.filter(topic=topic))
        context = {'menu': menu,
                   'topic': topic,
                   'comments': comments,
                   'comm_num': comments_number}
        return context


class AddTopic(LoginRequiredMixin, DataMixin, CreateView):
    form_class = AddTopicForm
    template_name = 'forum/addtopic.html'
    page_title = 'Создание новой темы'


class AddComment(LoginRequiredMixin, DataMixin, CreateView):
    form_class = AddCommentForm
    template_name = 'forum/addcomment.html'
    page_title = 'Оставить комментарий'
    success_url = reverse_lazy('topic')


class UpdateComment(LoginRequiredMixin, DataMixin, UpdateView):
    form_class = AddCommentForm
    template_name = 'forum/addcomment.html'
    page_title = 'Редактировать комментарий'
    success_url = reverse_lazy('topic')


class UserProfile(DetailView):
    model = Profile
    template_name = "profile.html"

forms.py:

from django import forms
from django.core.exceptions import ValidationError

#from forum.models import Topic, Comment


class AddTopicForm(forms.ModelForm):
    subject = forms.CharField(label="Заголовок", max_length=100, min_length=7)
    first_comment = forms.CharField(label="Сообщение", widget=forms.Textarea())

    class Meta:
        #model = Topic
        fields = ['subject', 'first_comment']

    def clean_subject(self):
        subject = self.cleaned_data['subject']
        if len(subject) > 100:
            raise ValidationError("Длина превышает 100 символов")
        if len(subject) < 7:
            raise ValidationError("Слишком короткое заглавие, требуется не менее 7 символов")
        return subject


class AddCommentForm(forms.ModelForm):
    content = forms.CharField(label="Текст комментария", max_length=2000, min_length=1, widget=forms.Textarea())

    class Meta:
        #model = Comment
        fields = ['content']

我不确定是否有必要,还给你urls.py:

from django.urls import path

from forum.views import *

urlpatterns = [
    #path('<slug:profile_slug>/', user_profile, name='user_profile'),
    path('', SubForumListView.as_view(), name='forum'),
    path('<slug:subforum_slug>/', TopicListView.as_view(), name='subforum'),
    path('subforum/<slug:topic_slug>/', ShowTopic.as_view(), name='topic'),
    path('subforum/add-topic/', AddTopic.as_view(), name="add_topic"),
    path('subforum/<slug:topic_slug>/add-comment/', AddComment.as_view(), name="add_comment"),
    path('subforum/<slug:topic_slug>/edit/<int:id>/', UpdateComment.as_view(), name="edit_comment"),

如果需要一些额外的文件/信息,我准备提供。目前,我无法继续实施该项目,因为 CI 不允许我测试论坛页面。所以我必须在采取进一步行动之前解决这个问题。

python django django-models
1个回答
0
投票

不要在模型中导入视图。视图应该依赖于模型,而不是相反。

您可以使用路径的名称,因此:

class Subforum(models.Model):
    # …

    def get_absolute_url(self):
        return reverse(
            'subforum',
            kwargs={'name': self.title, 'subforum_slug': self.slug},
        )

ShowTopic
相同,从而删除导入。


注意:您可以利用

django-autoslug
 [GitHub] 根据其他字段自动创建 slug。

© www.soinside.com 2019 - 2024. All rights reserved.