hagsteel / swampdragon

swampdragon
Other
557 stars 74 forks source link

has_related_value #196

Open borsdenold opened 8 years ago

borsdenold commented 8 years ago

I have two models: Board and User

class Board(SelfPublishModel, models.Model):
    serializer_class = router_serializers.BoardRouterSerializer
    title = models.CharField(max_length=20, verbose_name=u'Название')
    members = models.ManyToManyField(to='user.User', related_name='boards', verbose_name=u'Участники')
    def __unicode__(self):
        return self.title
class User(SelfPublishModel, AbstractBaseUser):
    serializer_class = router_serializers.UserRouterSerializer

    email = models.EmailField(
        verbose_name=u'Email',
        max_length=255,
        unique=True,
    )
    # Имя
    first_name = models.CharField(max_length=15, verbose_name=u"Имя", blank=True)

and I made UserRouter, where watch users, who have at least one common board with current login user.

class UserRouter(ModelRouter):
        ...
        def get_subscription_contexts(self, **kwargs):
            return {'boards__id__in': self.connection.user.boards.all().values_list("id", flat=True)}

But there was one problem: it did not automatically update list of boards ids. So, i decided, if user id is permanently constant, then it will be better use it.

    def get_subscription_contexts(self, **kwargs):
        return {'boards__members__id': self.connection.user.id}

But there are another problem, which i found in channel_utils.py in function has_related_value. It checks condition in this line: getattr(obj, property_name).filter(**{filter_by_val: channel_val}).exists() . But there it is getting current user relationship objects. So, i changed this line to obj.__class__.objects.filter(pk=obj.pk, **{field: channel_val}).exists() and it begin works correctly (at least, i think so). And i want to ask, is there any ways to make it without changing package code?

borsdenold commented 8 years ago

Additionaly:

def has_related_value(obj, field, channel_val):
    if '__' not in field:
        filter_by_val = channel_val
        property_name = field
    else:
        property_name, filter_by_val = field.split('__', 1)
    attr = getattr(obj, property_name)
    if hasattr(attr, 'all'):
        return getattr(obj, property_name).filter(**{filter_by_val: channel_val}).exists()
    else:
        filter_query = {'pk': obj.pk}
        filter_query[field] = channel_val
        return obj.__class__.objects.filter(**filter_query).exists()

Why there is condition if hasattr(attr, 'all'): ? In what events is it required? Perhaps, I am wrong, but I think, that

    filter_query = {'pk': obj.pk}
    filter_query[field] = channel_val
    return obj.__class__.objects.filter(**filter_query).exists()

will be work fine with every filter_query.