Django фильтрация отношений в models.py - PullRequest
1 голос
/ 11 марта 2020

Предполагается следующий сценарий в двух отдельных приложениях, где я хочу подсчитать количество элементов публикации определенной c категории в моем шаблоне:

Categories / models.py

from Posts.models import Post
...
class Category(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    title = models.CharField(max_length=20, verbose_name="Title")
    ...

    @property
    def posts(self):
        return Post.objects.filter(category_id=self.id).count()

Posts / models.py

class Post(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    title = models.CharField(verbose_name="Title")
    content = models.TextField(verbose_name="Content")
    tag = models.CharField(verbose_name="Meta", max_length=70, blank=True)
    category = models.ForeignKey(Category, on_delete=models.CASCADE, null=True)

шаблон. html:

<h5>Number of Post elements: {{ category.posts }}</h5>

к сожалению, это всегда приводит к следующей ошибке:

ImportError : невозможно импортировать имя 'Post' из частично инициализированного модуля 'Posts.models' (скорее всего, из-за циклического импорта)

Ответы [ 4 ]

1 голос
/ 11 марта 2020

Вероятно, это связано с тем, что вы импортируете Posts.models в свои Categories.models и наоборот . Вы можете импортировать это в самом свойстве:

# <i>no</i> from Posts.models import Post

# &hellip;

class Category(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    title = models.CharField(max_length=20, verbose_name="Title")
    # &hellip;

    @property
    def posts(self):
        from Posts.models import <b>Post</b>
        return Post.objects.filter(category_id=self.id).count()

Но вам не нужно импортировать эту модель. Django автоматически создает обратную связь. Если вы не укажете related_name, то есть modelname_set, поэтому вы можете получить доступ к нему с помощью:

# <i>no</i> from Posts.models import Post

# &hellip;

class Category(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    title = models.CharField(max_length=20, verbose_name="Title")
    # &hellip;

    @property
    def posts(self):
        return self.<b>post_set.count()</b>

Примечание : Python модули обычно записываются в snake_case , а не PerlCase , поэтому оно должно быть category, а не Category.

0 голосов
/ 11 марта 2020

Нет необходимости в этом свойстве, вы можете получить доступ к связанным объектам, следуя обратному внешнему ключу. См. документы

<h5>Number of Post elements: {{ category.post_set.count }}</h5>

Или вы можете добавить свойство, но напрямую:

@property
def post_count(self):
    return self.post_set.count()

А затем:

<h5>Number of Post elements: {{ category.post_count }}</h5>
0 голосов
/ 11 марта 2020

Подсказка в ошибке, поскольку у вас действительно есть циклический импорт.

Posts.models.py будет иметь from Categories.models import Category вверху, так как вы используете его в качестве внешнего ключа и, как вы Теперь используя Post в методе posts категории, он будет иметь from Posys.models import Post

. Вам нужно исправить это, что вы можете сделать одним из трех способов, в зависимости от того, есть ли у вас другие модели или методы, использующие класс Post изнутри Модель категорий.

Если вы это сделаете, то можете использовать один из этих двух

  1. Измените foreignKey для передачи строки, а не объекта Category, так что
class Post(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    title = models.CharField(verbose_name="Title")
    content = models.TextField(verbose_name="Content")
    tag = models.CharField(verbose_name="Meta", max_length=70, blank=True)
    category = models.ForeignKey("Category", on_delete=models.CASCADE, null=True)
Переместите импорт из верхней части Categories / models.py в методе posts, чтобы он импортировался локально
class Category(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    title = models.CharField(max_length=20, verbose_name="Title")

    @property
    def posts(self):
        from Posts.models import Post
        return Post.objects.filter(category_id=self.id).count()

Если вы этого не сделаете, и мы не можем определить, из чего после публикации вы можете просто использовать имя `` `post_set`` в классе Category и вообще избежать импорта. https://docs.djangoproject.com/en/3.0/topics/db/models/#be -careful-with-related-name-and-related-query-name

    @property
    def posts(self):
        return self.post_set.count()

Это также решит проблему

0 голосов
/ 11 марта 2020

Вы должны попробовать использовать связанное имя в вашей собственности:

class Category(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    title = models.CharField(max_length=20, verbose_name="Title")
    ...

    @property
    def posts(self):
        return self.post_set.count()

Кроме того, для записи кажется странным иметь Category и Post в отдельных приложениях. Скорее всего, они должны быть в одном blog приложении. Круговой импорт обычно подразумевает, что у вас есть два приложения, которые слишком тесно связаны. В этом случае, вероятно, должно быть только одно приложение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...