hagsteel / swampdragon

swampdragon
Other
557 stars 74 forks source link

update of model with "unique_together" problem #174

Closed siwiak closed 8 years ago

siwiak commented 8 years ago

Hi,

First of all, thank you for the great job!

I'm trying to show some to numerical value in real-time.

I created a button increasing a value (itemUp).

In controllers I have:

var AvResControllers = angular.module('AvResControllers', ['SwampDragonServices']);

AvResControllers.controller('AvResCtrl', ['$scope', '$dragon', function ($scope, $dragon) {
    $scope.channel = 'avress';
    $scope.resItems = [];

    $dragon.onReady(function() {
        $dragon.subscribe('avress-route', $scope.channel, {av_id: 98, 'update':0}).then(function(response) {
            $scope.dataMapper = new DataMapper(response.data);
        });

        $dragon.getList('avress-route', {av_id:98, 'update':0}).then(function(response) {
            $scope.resItems = response.data;
        });
    });

    $dragon.onChannelMessage(function(channels, message) {
        if (indexOf.call(channels, $scope.channel) > -1) {
            $scope.$apply(function() {
                $scope.dataMapper.mapData($scope.resItems, message);
            });
        }
    });

    $scope.itemUp = function(item) {
        $dragon.update('avress-route', {'count': item.count+1, 'av_id': 98, 'res_name': item.res_name, 'update':1}).then(function(response) {
    console.log(response.data);
});
        }
    }]);

(av_id is hardcoded untill I'll use swampdragon-auth)

in routers:

class AvResRouter(ModelRouter):
    route_name = 'avress-route'
    serializer_class = AvResSerializer
    model = AvatarResource

    def get_object(self, **kwargs):
        print("ME BE AvResRouter get_object")
        if kwargs['update'] != 0:
            res_up = self.model.objects.filter(av_id=kwargs['av_id'], res_name=kwargs['res_name']).update(count=kwargs['count'])
            return self.model.objects.get(
                av_id=kwargs['av_id'], res_name=kwargs['res_name'])
        else:
            return self.model.objects.get(
                av_id=kwargs['av_id'], res_name=kwargs['res_name'])

    def get_query_set(self, **kwargs):
        return self.model.objects.filter(av_id=kwargs['av_id'])

I know using kwargs['update'] is sorta hack, but this way at least values update...

and model

lass AvatarResource(models.Model):
    '''GAMEFILL initial 0'''
    serializer_class = AvResSerializer
    av_id = models.ForeignKey(Avatar, db_column='av_id', primary_key=True)
    res_name = models.ForeignKey('Resource', db_column='res_name')
    count = models.IntegerField()
    class Meta:
        managed = False
        db_table = 'planet_avatarresource'
        unique_together = ('av_id', 'res_name')

I have a problem -

ERROR:tornado.general:WebSocket Traceback (most recent call last): File "/usr/lib/python3/dist-packages/django/db/backends/utils.py", line 65, in execute return self.cursor.execute(sql, params) psycopg2.IntegrityError: duplicate key value violates unique constraint "planet_avatarresource_pkey" DETAIL: Key (av_id, res_name)=(98, C-Fibres) already exists.

I tried for a few days now, still I have no idea why this is an issue on UPDATE?

Than again - even when I UPDATE database using ugly hardcode in the routers, browser view does not. I need to reload the page.

Please help...

gnzlo789 commented 8 years ago

Hello, I don't think the problem with the database is related to Swampdragon, but you could try to edit the model from the admin panel, just to be sure. Maybe is not elegant but you could try to redefine the save method of your AvatarResource, looking for that row, avoiding duplication.

Than again - even when I UPDATE database using ugly hardcode in the routers, browser view does not. I need to reload the page.

You have two options, extend AvatarResource from SelfPublishModel:

class AvatarResource(SelfPublishModel, models.Model):
    '''GAMEFILL initial 0'''
    serializer_class = AvResSerializer
    av_id = models.ForeignKey(Avatar, db_column='av_id', primary_key=True)
    res_name = models.ForeignKey('Resource', db_column='res_name')
    count = models.IntegerField()
    class Meta:
        managed = False
        db_table = 'planet_avatarresource'
        unique_together = ('av_id', 'res_name')

OR

Use ModelPubRouter.

class AvResRouter(ModelPubRouter):
    route_name = 'avress-route'
    serializer_class = AvResSerializer
    model = AvatarResource

    def get_object(self, **kwargs):
        print("ME BE AvResRouter get_object")
        if kwargs['update'] != 0:
            res_up = self.model.objects.filter(av_id=kwargs['av_id'], res_name=kwargs['res_name']).update(count=kwargs['count'])
            return self.model.objects.get(
                av_id=kwargs['av_id'], res_name=kwargs['res_name'])
        else:
            return self.model.objects.get(
                av_id=kwargs['av_id'], res_name=kwargs['res_name'])

    def get_query_set(self, **kwargs):
        return self.model.objects.filter(av_id=kwargs['av_id'])
siwiak commented 8 years ago

Hi,

Thanks for the answer! None of those solutions worked for me (tried them before). I found in the console that an error is:

ReferenceError: channel is not defined

I think it might be problem with iceweasel and chrome discussed here in one of the issues. I think it's supposed to be solved in 0.4.3, but I didn't find a way to install it (I downloaded it, unzipped into 0.4.2.2. location, but still when I run server it says 0.4.2.2)

gnzlo789 commented 8 years ago

Hi, you need to use SelfPublishModel or ModelPubRouter if you want to see real time updates.

Why are you updating the value of count in the get_object method?

if kwargs['update'] != 0:
    res_up = self.model.objects.filter(av_id=kwargs['av_id'], res_name=kwargs['res_name']).update(count=kwargs['count'])
    return self.model.objects.get(
        av_id=kwargs['av_id'], res_name=kwargs['res_name'])

get_object should only retrive one item. When you call the update method, it will try to update it too.

To install Swampdragon 0.4.3:

pip install https://github.com/jonashagstedt/swampdragon/archive/0.4.3.zip
siwiak commented 8 years ago

Hi, I use it to go around previously mentioned problem with update. When I call $dragon.update I get an error with duplicate key. I modified get method to accept 'update' kwarg. Now instead of calling $dragon.update, I call $dragon.get('avress-route', {... {'update':1})... When I need a regular $dragon.get, I simply use {'update':0}. Nasty, but functional. Thanks for the install instruction!

siwiak commented 8 years ago

0.4.3 no longer has this problem, closing the issue.