Я использую комбинацию Django, GraphQL (graphene- django), VueJS и Apollo Client для моего проекта. Все работает нормально, пока я не попытался управлять многими отношениями. Обычно, когда я делаю мутацию обновления для объекта, который уже находится в кэше, он обнаруживается, и отображаемые данные обновляются. Проблема в том, что в моем новом случае я обновляю отношение many2many между моими двумя объектами, и оно не обновляется, пока оно правильно выполняется в базе данных (и даже в кэше, когда я печатаю его в консоли, которая странно). Как правило, я пытаюсь добавить / удалить пользователей в / из группы. Может быть, я смотрю свой код в течение слишком долгого времени, и я не вижу ничего очевидного .. В любом случае вот мой код:
Мои Django модели:
class Group(models.Model):
def _get_users_count(self):
return self.user_ids.count()
name = models.CharField(max_length=255)
user_ids = models.ManyToManyField(User, related_name="group_ids", db_table="base_group_user")
users_count = property(fget=_get_users_count, doc="type: Integer")
def __str__(self):
return self.name
class User(AbstractUser):
def _get_full_name(self):
return "%s %s" % (self.first_name, self.last_name.upper())
full_name = property(fget=_get_full_name, doc="type: String")
def __str__(self):
return self.full_name
def _has_group(self, group_name):
return self.group_ids.filter(name=group_name).exists()
Мои схемы:
class GroupType(DjangoObjectType):
class Meta:
model = Group
fields = ('id', 'name', 'user_ids',)
users_count = graphene.Int()
class UserType(DjangoObjectType):
class Meta:
model = User
fields = (
'id',
'username',
'password',
'first_name',
'last_name',
'is_active',
'group_ids',
)
full_name = graphene.String()
Мои мутаторы:
class AddUserInGroup(graphene.Mutation):
id = graphene.ID()
name = graphene.String()
class Arguments:
group_id = graphene.ID()
user_id = graphene.ID()
class Meta:
output = GroupType
def mutate(self, info, **kwargs):
group = get_object_or_404(Group, id=kwargs['group_id'])
user = get_object_or_404(User, id=kwargs['user_id'])
group.user_ids.add(user)
return group
class RemoveUserFromGroup(graphene.Mutation):
id = graphene.ID()
name = graphene.String()
class Arguments:
group_id = graphene.ID()
user_id = graphene.ID()
class Meta:
output = GroupType
def mutate(self, info, **kwargs):
group = get_object_or_404(Group, id=kwargs['group_id'])
user = get_object_or_404(User, id=kwargs['user_id'])
group.user_ids.remove(user)
return group
Мои js константы (запросы gql):
const ADD_USER_IN_GROUP_MUTATION = gql`
mutation addUserInGroupMutation ($groupId: ID!, $userId: ID!) {
addUserInGroup(
groupId: $groupId,
userId: $userId
) {
id
name
usersCount
userIds {
id
username
}
}
}
`
const REMOVE_USER_FROM_GROUP_MUTATION = gql`
mutation remoteUserFromGroupMutation ($groupId: ID!, $userId: ID!) {
removeUserFromGroup(
groupId: $groupId,
userId: $userId
) {
id
name
usersCount
userIds {
id
username
}
}
}
`
const GROUPS_QUERY = gql`
query {
groups {
id
name
usersCount
userIds {
id
username
}
}
}
`
Мой шаблон (образец): Это 2 столбца. Когда я удаляю пользователя, он должен быть удален из левого столбца, и он должен появляться у пользователей, которых нет в группе (правый столбец), а когда я добавляю пользователя, он должен go из правого столбца слева один.
<b-tab>
<template v-slot:title>
Users
<b-badge class="ml-2">{{ group.usersCount }}</b-badge>
</template>
<b-row>
<b-col>
<b-table :items="group.userIds" :fields="table_fields_users_in">
<template v-slot:cell(actionOut)="row">
<b-button @click="removeUserFromGroup(row.item)" size="sm" variant="danger" title="Remove">
<font-awesome-icon :icon="['fas', 'minus-circle']"/>
</b-button>
</template>
</b-table>
</b-col>
<b-col>
<b-table :items="users" :fields="table_fields_users_out">
<template v-slot:cell(actionIn)="row">
<b-button @click="addUserInGroup(row.item)" size="sm" variant="success" title="Add">
<font-awesome-icon :icon="['fas', 'plus-circle']"/>
</b-button>
</template>
</b-table>
</b-col>
</b-row>
</b-tab>
Мои данные: (чтобы вы могли понять, откуда они взялись). Обратите внимание, что я должен уточнить слова «пользователи» для пользователей, которых еще нет в группе.
props: {
group: Object,
editing: {
type: Boolean,
default: false
}
},
apollo: { users: USERS_QUERY },
и, наконец, мои методы :
addUserInGroup (user) {
this.$apollo.mutate({
mutation: ADD_USER_IN_GROUP_MUTATION,
variables: {
groupId: this.group.id,
userId: user.id
},
update: (cache, { data: { addUserInGroup } }) => {
console.log('cache : ') // currently used for debugging, will be removed
console.log(cache) // currently used for debugging, will be removed
console.log('query answer: ') // currently used for debugging, will be removed
console.log(addUserInGroup) // currently used for debugging, will be removed
}
})
console.log('Added ' + user.username + ' to ' + this.group.name + ' group.')
},
removeUserFromGroup (user) {
this.$apollo.mutate({
mutation: REMOVE_USER_FROM_GROUP_MUTATION,
variables: {
groupId: this.group.id,
userId: user.id
},
update: (cache, { data: { removeUserFromGroup } }) => {
console.log('cache : ') // currently used for debugging, will be removed
console.log(cache) // currently used for debugging, will be removed
console.log('query answer : ') // currently used for debugging, will be removed
console.log(removeUserFromGroup) // currently used for debugging, will be removed
}
})
console.log('Removed ' + user.username + ' from ' + this.group.name + ' group.')
}
Если вам, ребята, нужно больше кода (некоторые части я бы забыл), не стесняйтесь, сообщите мне, и я предоставлю его.
Пример того, что я делаю (так что вы заметите, что мои демонстрационные данные буквально сделаны, разбивая мою клавиатуру):