hagsteel / swampdragon

swampdragon
Other
557 stars 73 forks source link

Subscriptions does not fills the scope as expected for related models #121

Open ghost opened 9 years ago

ghost commented 9 years ago

Models:

class General(SelfPublishModel, models.Model):
    serializer_class = GeneralSerializer
    nickname = models.CharField(max_length=30, unique=True)
    empire = models.ForeignKey('Empire', related_name='members', null=True, blank=True)

class Empire(SelfPublishModel, models.Model):
    serializer_class = EmpireSerializer
    name = models.CharField(max_length=50)
    acronym = models.CharField(max_length=5)

Serializers:

class GeneralSerializer(ModelSerializer):
    empire = 'EmpireSerializer'
    class Meta:
        model = 'game.General'
        publish_fields = ('nickname', 'empire')

class EmpireSerializer(ModelSerializer):
    class Meta:
        model = 'game.Empire'
        publish_fields = ('name', 'acronym')

Router:

class GeneralRouter(ModelRouter):
    route_name = 'general'
    model = General
    serializer_class = GeneralSerializer
    include_related = [EmpireSerializer]

    def get_object(self, **kw):
        return self.model.objects.get(pk=kw['id'])

    def get_query_set(self, **kw):
        return self.model.objects.all()

When I use $dragon.getSingle('general', {id: 1}) on the client side, the scope is filled as expected with {nickname: "Metathink", empire: {name: "Unlimited", acronym: "UNL"}}.

But when I modify the General model in the django admin, I receive an updated action and the scope is filled with {nickname: "Metathink", empire: 1}.

I don't understand why empire is set to 1 when I modify the General model.

hagsteel commented 9 years ago

Does the General have an Empire with a PK of 1 perhaps?

Rather than getting the entire empire model from the db it simply returns the primary key, it's up to the front end to map this. The datamapper handles this for you

ghost commented 9 years ago

Yes it has a pk of 1.

The selfpub_example has the same issue. When you load the page, everything works fine, but when you modify for exemple the name of a company on the django admin, the related models (staff in this case) are set to the primary key instead of an Object. The problem is that angular uses this (the scope filled by datamapper) to fill his page. And if staff is a primary key and not an Object, the staff information and the documents related to the staff goes blank.

When the page loads $dragon.getList('company-route', {}) is called, everything is ok because the related models are represented by an Object, but when a subscription event is received, all the related models are represented by a primary key instead of an Object.

Is it a bug or do I need to do something special to ask the subscriptions events to received an Object instead of a primary key like $dragon.getList and $dragon.getSingle does?

hagsteel commented 9 years ago

Which version of SD are you using?

ghost commented 9 years ago

The github one.

hagsteel commented 9 years ago

Which branch

ghost commented 9 years ago

The master I guess, I'v put git+https://github.com/jonashagstedt/swampdragon.git in my requirements.txt

ghost commented 9 years ago

I'v tried with the branch 0.4.3 and the issue is still here both for the selfpub_example and my project.

hagsteel commented 9 years ago

I'd say if it's not working as you expect it to, then manually publish the models. The SelfPubModel is not a silver bullet by any means

ghost commented 9 years ago

So, I should use two serializers for the same model? One on the ModelRouter for using getList and getSingle to retrieve a model and its relations, and another one on the django Model to be notified that a model has been edited?

This is very confusing. I do not understand why $dragon.subscribe uses the same router than $dragon.getSingle and $dragon.getList but does not follow the same rules for relations. This should be written somewhere in the documentation.

ghost commented 9 years ago

Hum sorry, maybe the problem is somewhere else. I just realised that when an entry of a model is updated, only the updated entry is pushed to the frontend. Except if we set a serializer for a related model. For example:

class GeneralSerializer(ModelSerializer):
    class Meta:                                 
        model = 'game.General'                  
        publish_fields = ('nickname', 'empire')

^ If I modify the nickname on the django admin, only the nickname is pushed to the frontend.

class GeneralSerializer(ModelSerializer):
    empire = 'EmpireSerializer'
    class Meta:                                 
        model = 'game.General'                  
        publish_fields = ('nickname', 'empire')

^ This time, if I modify the nickname on the django admin, the nickname and the empire ID is pushed, even if i did not modified the empire, this is why everything is broken on the selfpub_example too, because angularJS is waiting for an Object, not an ID.

Is this the excepted behavior?

To fix the problem, I created 2 serializers, one on the ModelRouter with empire = 'EmpireSerializer' and another one on the django SelfPublishModel without empire = 'EmpireSerializer'.

BuckinghamIO commented 9 years ago

@metathink I am having the same issue with related models as well and I have been told the same response however with the way it is currently the update action may as well not even publish the fact a foreignkey excist since it removes data from the front end like you also say.

I have provided a method of changing this in my ticket which I will be updating as I know of a better way.

ghost commented 9 years ago

Thank you to both of you.