获取Django模型中的多对多关系与我的其他模型相对应。

huangapple go评论65阅读模式
英文:

fetch Django model in many to many relationship my other model

问题

我正在尝试弄清楚一个Django模型与另一个模型的特定对象具有多对多关系的对象数量。

我的models.py如下:

from django.db import models
from django.contrib.auth.models import User

class Post(models.Model):
    post_title = models.CharField(max_length=200)
    post_body = models.CharField(max_length=1000)
    pub_date = models.DateTimeField('date published')
    by = models.ForeignKey(User, on_delete=models.CASCADE)
    
    def __str__(self):
        return self.post_title
    
    def get_id(self):
        return self.id
    
    def get_body(self):
        return self.post_body
    
    def get_date(self):
        return self.pub_date
    
    def get_name(self):
        return self.post_title
    
    def get_author(self):
        return self.by
    
    def get_likes(self):
        return type(self).likes.all()

class Like(models.Model):
    associated_post = models.ManyToManyField(Post)
    associated_user = models.ManyToManyField(User)

我的视图如下:

from django.views import generic
from django.shortcuts import render
from django.http import HttpResponse, HttpResponseRedirect
from django.utils import timezone

from .models import Post

def index(request):
    posts = []
    
    for post in Post.objects.order_by('-pub_date'):
        posts.append({'title': post.get_name(), 'author_id': str(post.get_author()), 'created': post.get_date(), 'body': post.get_body(), 'id': post.get_id()})
        print(post.get_likes())
    return render(request, 'home.html', {'posts': posts})

基本上,post.get_likes 函数需要返回与帖子相关的喜欢的数量。

我已经阅读了Django文档关于这个主题的部分,但我仍然无法完全理解示例代码中发生的事情。

英文:

I am trying to figure out how many objects of a djanog model have a many to many relationship with a spicific objects of another model.

my models.py is

from django.db import models
from django.contrib.auth.models import User

class Post(models.Model):
    post_title = models.CharField(max_length=200)
    post_body = models.CharField(max_length=1000)
    pub_date = models.DateTimeField('date published')
    by = models.ForeignKey(User, on_delete=models.CASCADE)
    def __str__(self):
        return self.post_title
    def get_id(self):
        return self.id
    def get_body(self):
        return self.post_body
    def get_date(self):
        return self.pub_date
    def get_name(self):
        return self.post_title
    def get_author(self):
        return self.by
    def get_likes(self):
        return type(self).likes.all()

class Like(models.Model):
    associated_post = models.ManyToManyField(Post)
    associated_user = models.ManyToManyField(User)

and my view is

from django.views import generic
from django.shortcuts import render
from django.http import HttpResponse, HttpResponseRedirect
from django.utils import timezone

from .models import Post

def index(request):
    posts = []
    
    for post in Post.objects.order_by('-pub_date'):
        posts.append({'title': post.get_name(), 'author_id': str(post.get_author()), 'created': post.get_date(), 'body': post.get_body(), 'id': post.get_id()})
        print(post.get_likes())
    return render(request, 'home.html', {'posts': posts})

Basically the function post.get_likes needs to return the number of likes that have a realtionship with the post.

I v'e read the django documentation on this topic, but I just can't quite figure out what is actually going on in the example code.

答案1

得分: 1

Like 的建模方式有些奇怪,一个 Like 应该是指一个单独的帖子(Post)上的一个单独的点赞,因此:

from django.conf import settings

class Like(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='likes')
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='likes'
    )

因此,一个 Like 可以关联到一个特定的 Post 和用户,因此每个 Post 可能有多个 Like,而一个用户也可以有多个 Like

至于 Post 模型,在 Python 中通常不需要编写 "getter" 函数:可以直接像访问属性一样获取属性。因此,Post 模型可以如下所示:

from django.conf import settings

class Post(models.Model):
    title = models.CharField(max_length=200)
    body = models.CharField(max_length=1000)
    pub_date = models.DateTimeField('date published')
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

    def __str__(self):
        return self.title

在视图中,您也不需要 "序列化" 数据,只需将模型对象传递给模板:

from django.db.models import Prefetch

def index(request):
    posts = Post.objects.prefetch_related(
        Prefetch('like', Like.objects.select_related('user'))
    ).order_by('-pub_date')
    return render(request, 'home.html', {'posts': posts})

在模板中,只需呈现数据:

{% for post in posts %}
    {{ post }}
    likes:
    <ul>
    {% for like in post.likes.all %}
        {{ like.user }}
    {% endfor %}
    </ul>
{% endfor %}
英文:

The modeling of the Like is strange, a Like should likely refer to a single item with a single Post, so:

<pre><code>from django.conf import settings

class Like(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='likes')
user = models.ForeignKey(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='likes'
)</code></pre>

So a Like can refer to a combination of Post and user, and thus each Post can have multiple Likes and a user can have multiple Likes as well.

as for the the Post model, in Python typically one does not write getters: the attributes can be retrieved just as attributes. So the post model can look like:

<pre><code>from django.conf import settings

class Post(models.Model):
title = models.CharField(max_length=200)
body = models.CharField(max_length=1000)
pub_date = models.DateTimeField('date published')
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

def __str__(self):
    return self.title&lt;/code&gt;&lt;/pre&gt;

In the view, you also do not need to "serialize" the data, you can just pass the model objects to the template:

<pre><code>from django.db.models import Prefetch

def index(request):
posts = Post.objects<b>.prefetch_related(
Prefetch('like', Like.objects.select_related('user'))
)</b>.order_by('-pub_date')
return render(request, 'home.html', {'posts': posts})</code></pre>

In the template you just render the data:

{% for post in posts %}
    {{ post }}
    likes:
    &lt;ul&gt;
    {% for like in post.likes.all %}
        {{ like.user }}
    {% endfor %}
    &lt;/ul&gt;
{% endfor %}

答案2

得分: 0

以下是翻译好的部分:

首先`models.py` 文件中您不需要为每个属性编写获取器函数您可以直接使用 `.` 符号从对象中引用单个属性例如 `post.id`,其中 `post` 是来自 `Post` 模型的对象

您的 `models.py` 可以只定义属性如下所示

```python
from django.db import models
from django.contrib.auth.models import User

class Post(models.Model):
    title = models.CharField(max_length=200)
    body = models.CharField(max_length=1000)
    published_date = models.DateTimeField('date published')
    created_by = models.ForeignKey(User, on_delete=models.CASCADE)

我已根据以下最佳实践更改了属性的命名:

  • 模型的命名空间指示为 post,因此不需要在属性前面加上相同的名称前缀。
  • 使用有意义的详细名称,如 published_datecreated_by,以便任何人都能更容易阅读并理解上下文。

您的中间表或联接表关系应具有对两个表的外键关系,如下所示:

class Like(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='likes')
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='likes')

要获取点赞的数量,您不需要在管理器上使用 .all() 方法。这将返回该帖子的所有点赞(如果您的帖子有 10,000 个点赞,它将全部加载到内存中)。您实际上需要的是计数,所以可以执行 post.likes.count()。您还可以在查询集上注释点赞数量。

最终的视图应该如下所示:

from django.views import generic
from django.shortcuts import render
from django.http import HttpResponse, HttpResponseRedirect
from django.utils import timezone
from django.db.models import Count

from .models import Post

def index(request):
    posts = Post.objects.order_by("-published_date").annotate(num_likes=Count("likes"))
    return render(request, 'home.html', {'posts': posts})

然后,您可以直接在模板中使用 posts,并使用 {{ post.num_likes }} 来显示该帖子的点赞数。


<details>
<summary>英文:</summary>

First, your model in `models.py` file does not need a getter function for every attribute. You can just reference the individual attribute from an object using the `.` notation like `post.id` where `post` is an object from the `Post` model.

Your `models.py` can just define the attributes like:

    from django.db import models
    from django.contrib.auth.models import User

    class Post(models.Model):
        title = models.CharField(max_length=200)
        body = models.CharField(max_length=1000)
        published_date = models.DateTimeField(&#39;date published&#39;)
        created_by = models.ForeignKey(User, on_delete=models.CASCADE)

I&#39;ve changed the naming of attributes here based on the following best practices:

- The namespace for the model indicates `post` so, no need to name attributes prefixing the same name.
- Using meaningful elaborated names like `published_date` and `created_by` so that they are easier to read and gain context for anyone.

Your through-table or join-table relationship should have a Foreign-Key relationship to both tables like:

    class Like(models.Model):
        post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name=&#39;likes&#39;)
        user = models.ForeignKey(User, on_delete=models.CASCADE, related_name=&#39;likes&#39;)

For getting the count of likes, you don&#39;t need the `.all()` method on the manager. That returns all the likes of that post (if you have 10K likes on the post, it will bring all of those in the memory), but what you really want is to count, so you can do `post.likes.count()`. You can also annotate the number of likes on your queryset.

The final view should look something like this:

    from django.views import generic
    from django.shortcuts import render
    from django.http import HttpResponse, HttpResponseRedirect
    from django.utils import timezone
    from django.db.models import Count

    from .models import Post


    def index(request):
        posts = Post.objects.order_by(&quot;-published_date&quot;).annotate(num_likes=Count(&quot;likes&quot;))
        return render(request, &#39;home.html&#39;, {&#39;posts&#39;: posts})

You can then use `posts` directly in your template and use `{{ post.num_likes }}` to display the no of likes on that post.

</details>



huangapple
  • 本文由 发表于 2023年2月27日 03:47:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/75574611.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定