Skip to content

查询我关注的及屏蔽的用户 #12

@codetalks-new

Description

@codetalks-new

开发及测试数据准备

  1. 通过迁移脚本创建一些互相关注或屏蔽的开发用户
    ./manage_dev.py makemigrations wepost_sns --empty --name dev_user_follow_some_user

迁移脚本如下:

from django.db import migrations

from wepost.apps.auth.models import WepostUser
from wepost.apps.sns.services import UserRelationService


def dev_user_follow_block_some_users(apps,se):
    import random
    dev_users = list(WepostUser.objects.filter(username__istartswith="dev"))
    user_set = set(dev_users)
    for user in user_set:
        service = UserRelationService(user)
        other_users = set(user_set)
        other_users.remove(user)
        k = int(len(other_users) * 0.1)
        blocked_users = set(random.choices(list(other_users), k=k))
        for to in other_users:
            if to not in blocked_users:
              service.follow(to)
            else:
              service.block(to)





class Migration(migrations.Migration):

    dependencies = [
        ('wepost_sns', '0001_initial'),
    ]

    operations = [
        migrations.RunPython(dev_user_follow_block_some_users)
    ]

创建多对多关联

class WepostUser(AbstractUser):
  followed_or_blocked = models.ManyToManyField('self',
                                               symmetrical=False,
                                               through='wepost_sns.UserRelation',
                                               through_fields=('from_user', 'to_user'))

注意

  1. 这里的多对多关联是关联的自身上。所以引用时使用特殊的 self 标识。
  2. 同时在我们这里采用了中间表,并且表示的也并非对称性的关系,所以 symmetrical=False
  3. through 字段中由于 UserRelation 数据模型声明在 wepost_sns app中。所以在 wepost_auth app 中引用需要加全限定。
  4. through_fields 中两个字段的逻辑是 field1from_user 相当于 source, field2to_user 相当于 target.

原来 from_userto_user 的 related_name 的设置的名称的语义不正确。更新后如下:

class UserRelation(BaseModel):
  from_user = models.ForeignKey(WepostUser, on_delete=models.CASCADE, verbose_name="用户",
                                related_name="userrelation_from", )
  to_user = models.ForeignKey(WepostUser, on_delete=models.CASCADE, verbose_name="目标用户", related_name="userrelation_to")

然后实现的查询接口代码如下:

  def _query_related(self, state: UserRelationState, keyword: str = None):
    user_set = self.user.followed_or_blocked.filter(userrelation_to__state=state).order_by(
      "-userrelation_to__created")
    if keyword:
      user_set = user_set.filter(username__icontains=keyword)

    return user_set

  def query_followed_users(self, keyword: str = None):
    return self._query_related(state=UserRelationState.FOLLOWING, keyword=keyword)

  def query_blocked_users(self, keyword: str = None):
    return self._query_related(state=UserRelationState.BLOCKING, keyword=keyword)

测试相关代码,跟我的节点中测试代码逻辑类同,因此在此不再赘述。

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions