Извлечение внешнего соединения из Django ORM - PullRequest
0 голосов
/ 25 октября 2019

У меня есть следующие две модели в моем проекте.

class Blog(models.Model):   
    title=models.CharField(max_length=20, blank=False, default='')
    content=models.CharField(max_length=2000, blank=False, default='')

class UserLikedBlogs(models.Model):
    blog=models.ForeignKey(TTSServiceModel.TTSService, on_delete=models.CASCADE, blank=True, null=True)
    user=models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

Все пользователи, которые могут войти, могут видеть блоги других пользователей. Текущий вошедший в систему пользователь может «полюбить» определенный блог, который добавляет запись в таблицу UserLikedBlogs.

Теперь я хочу показать все блоги, присутствующие в системе, зарегистрированному пользователю, но я также хочу показать блоги, которые понравились пользователю.

Я понимаю, что это должно получить все записи из таблицы блогов с дополнительными столбцами из таблицы UserLikedBlogs, где данные присутствуют только для блогов, понравившихся пользователю, а не иначе.

Этоклассический случай Внешнего Соединения, где общие элементы между двумя наборами связаны со всеми элементами из одной из таблиц, участвующих в объединении.

Я читал документацию от django и на SO, но я не могукажется, найти правильный синтаксис для этого.

Мой хакерский способ сделать это - использовать пользователя Pandas и соединить два набора данных в Python, а не запрос. Я уверен, что есть лучший способ, но просто не могу его найти. Вы можете помочь?

Ответы [ 3 ]

1 голос
/ 25 октября 2019

Вероятно, вы можете попробовать вот так:

Blog.objects.filter(userlikedblogs__user=request.user)

Здесь я использую reverse relation между UserLikedBlogs и Blog, чтобы получить блогиПонравилось пользователю.


Обновление на основе комментария, добавленного OP в нижней части этого ответа:

Здесь, в основном, вы хотите аннотировать информацию, нравится ли пользователю блог или нет. Вы можете сделать это, используя conditional expressions:

from django.db.models import Case, Value, BooleanField

blogs = Blog.objects.annotate(
     liked=Case(
         When(userlikedblogs__user=request.user, then=Value(True)),
         default=Value(False),
         output_field=BooleanField(),
     )
)

И использовать эти блоги в template (когда вы отправляете их через контекст из представления в шаблон):

{% for blog in blogs %}
    {% if blog.liked %}
        <a style="background:blue" href="{% url 'blog:detail' blog.pk %}">{{ blog.title }}</a>
    {% else %}
        <a style="background:green" href="{% url 'blog:detail' blog.pk %}">{{ blog.title }}</a>
    {% endif %}
{% endfor %}
0 голосов
/ 27 октября 2019

Я закончил тем, что сделал следующее

allLikedBlogs=Blogs.objects.all().values('title', 'content', 'userlikedblogs__user')

Это привело к тому, что ORM сделал левое внешнее соединение.

0 голосов
/ 25 октября 2019

Все блоги видны зеленым шрифтом. Некоторые блоги нравятся пользователю, и они должны отображаться в виде шрифта синего цвета.

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

Blog.objects.annotate(is_favorite=Exists(UserLikedBlogs.objects.filter(blog=OuterRef('pk'), user=request.user)))

, тогда в своем шаблоне вы можете просто проверить blog.is_favorite, чтобы увидеть, является ли он предпочтительным для текущего пользователя

...