英文:
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 Like
s and a user can have multiple Like
s 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</code></pre>
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:
<ul>
{% for like in post.likes.all %}
{{ like.user }}
{% endfor %}
</ul>
{% 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_date
和created_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('date published')
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
I'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='likes')
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='likes')
For getting the count of likes, you don'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("-published_date").annotate(num_likes=Count("likes"))
return render(request, 'home.html', {'posts': 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>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论