david / django-roa (http://welldev.org/)

Turn your models into remote resources that you can access through Django's ORM. ROA stands for Resource Oriented Architecture.

Clone this repository (size: 560.7 KB): HTTPS / SSH
$ hg clone http://code.welldev.org/django-roa
commit 131: 3e613d59de36
parent 130: 2616a61bffb2
branch: default
Compatibility with Django 1.2 alpha *but* M2M relations do not work for now, still a work in progress though
David Larlet / david
8 months ago

Changed (Δ2.5 KB):

raw changeset »

django_roa/db/models.py (14 lines added, 4 lines removed)

django_roa/db/query.py (14 lines added, 57 lines removed)

examples/django_roa_client/models.py (3 lines added, 3 lines removed)

examples/django_roa_client/tests.py (3 lines added, 1 lines removed)

Up to file-list django_roa/db/models.py:

@@ -114,6 +114,8 @@ class ROAModelBase(ModelBase):
114
114
                    new_class._meta.local_many_to_many):
115
115
                raise FieldError("Proxy model '%s' contains model fields."
116
116
                        % name)
117
            while base._meta.proxy:
118
                base = base._meta.proxy_for_model
117
119
            new_class._meta.setup_proxy(base)
118
120
119
121
        # Do the appropriate setup for any model parents.
@@ -121,6 +123,7 @@ class ROAModelBase(ModelBase):
121
123
                if isinstance(f, OneToOneField)])
122
124
123
125
        for base in parents:
126
            original_base = base
124
127
            if not hasattr(base, '_meta'):
125
128
                # Things without _meta aren't functional models, so they're
126
129
                # uninteresting parents.
@@ -165,7 +168,7 @@ class ROAModelBase(ModelBase):
165
168
            # Proxy models inherit the non-abstract managers from their base,
166
169
            # unless they have redefined any of them.
167
170
            if is_proxy:
168
                new_class.copy_managers(base._meta.concrete_managers)
171
                new_class.copy_managers(original_base._meta.concrete_managers)
169
172
170
173
            # Inherit virtual fields (like GenericForeignKey) from the parent
171
174
            # class
@@ -242,8 +245,8 @@ class ROAModel(models.Model):
242
245
    def get_resource_url_detail(self):
243
246
        return u"%s%s/" % (self.get_resource_url_list(), self.pk)
244
247
    
245
    def save_base(self, raw=False, cls=None, origin=None,
246
            force_insert=False, force_update=False):
248
    def save_base(self, raw=False, cls=None, origin=None, force_insert=False, 
249
            force_update=False, using=None):
247
250
        """
248
251
        Does the heavy-lifting involved in saving. Subclasses shouldn't need to
249
252
        override this method. It's separate from save() in order to hide the
@@ -259,7 +262,7 @@ class ROAModel(models.Model):
259
262
        else:
260
263
            meta = cls._meta
261
264
262
        if origin:
265
        if origin and not meta.auto_created:
263
266
            signals.pre_save.send(sender=origin, instance=self, raw=raw)
264
267
265
268
        # If we are in a raw save, save the object exactly as presented.
@@ -382,6 +385,13 @@ class ROAModel(models.Model):
382
385
383
386
    delete.alters_data = True
384
387
388
    def _get_unique_checks(self):
389
        """
390
        We don't want to check unicity that way for now.
391
        """
392
        unique_checks, date_checks = [], []
393
        return unique_checks, date_checks
394
385
395
386
396
##############################################
387
397
# HELPER FUNCTIONS (CURRIED MODEL FUNCTIONS) #

Up to file-list django_roa/db/query.py:

@@ -64,7 +64,7 @@ class Query(object):
64
64
        self.select_related = field_dict
65
65
        self.related_select_cols = []
66
66
        self.related_select_fields = []
67
    
67
68
68
    @property
69
69
    def parameters(self):
70
70
        """
@@ -135,6 +135,7 @@ class RemoteQuerySet(query.QuerySet):
135
135
        self._result_cache = None
136
136
        self._iter = None
137
137
        self._sticky_filter = False
138
        self._db = False
138
139
        
139
140
        self.params = {}
140
141
    
@@ -406,66 +407,22 @@ class RemoteQuerySet(query.QuerySet):
406
407
            return FakeInt(self.count())
407
408
        raise ROANotImplementedYetException, 'extra is not yet fully implemented.'
408
409
409
    #################################
410
    # METHODS THAT DO M2M RELATIONS #
411
    #################################
412
413
    def _add_items(self, source_col_name=None, target_col_name=None, 
414
                   join_table=None, pk_val=None, instance=None, field=None, 
415
                   *objs):
416
        """
417
        Adds m2m relations between ``instance`` object and ``objs``.
418
        """
419
        if objs:
420
            from django.db.models.base import Model
421
            # Check that all the objects are of the right type
422
            existing_ids = set(obj.id for obj in field.value_from_object(instance))
423
            for obj in objs:
424
                if isinstance(obj, self.model):
425
                    existing_ids.add(obj._get_pk_val())
426
                elif isinstance(obj, Model):
427
                    raise TypeError, "'%s' instance expected" % self.model._meta.object_name
428
                else:
429
                    existing_ids.add(obj)
430
            # FIXME: ugly but we set manually updated_ids to the instance
431
            # before saving it, get back in save_model to send appropriated
432
            # ids to the server
433
            setattr(instance, '%s_updated_ids' % field.attname, existing_ids)
434
            instance.save()
435
436
    def _remove_items(self, source_col_name=None, target_col_name=None, 
437
                      join_table=None, pk_val=None, instance=None, field=None, 
438
                      *objs):
439
        """
440
        Removes m2m relations between ``instance`` object and ``objs``.
441
        """
442
        if objs:
443
            from django.db.models.base import Model
444
            # Check that all the objects are of the right type
445
            existing_ids = set(obj.id for obj in field.value_from_object(instance))
446
            for obj in objs:
447
                if isinstance(obj, self.model):
448
                    existing_ids.remove(obj._get_pk_val())
449
                elif isinstance(obj, Model):
450
                    raise TypeError, "'%s' instance expected" % self.model._meta.object_name
451
                else:
452
                    existing_ids.remove(obj)
453
            setattr(instance, '%s_updated_ids' % field.attname, existing_ids)
454
            instance.save()
455
456
    def _clear_items(self, source_col_name=None, join_table=None, pk_val=None, 
457
                     instance=None, field=None):
458
        """
459
        Clears m2m relations related to ``instance`` object.
460
        """
461
        setattr(instance, '%s_updated_ids' % field.attname, [])
462
        instance.save()
463
464
465
410
    ###################
466
411
    # PRIVATE METHODS #
467
412
    ###################
468
413
414
    def _clone(self, klass=None, setup=False, **kwargs):
415
        if klass is None:
416
            klass = self.__class__
417
        query = self.query.clone()
418
        if self._sticky_filter:
419
            query.filter_is_sticky = True
420
        c = klass(model=self.model, query=query)
421
        c.__dict__.update(kwargs)
422
        if setup and hasattr(c, '_setup_query'):
423
            c._setup_query()
424
        return c
425
469
426
    def _as_url(self):
470
427
        """
471
428
        Returns the internal query's URL and parameters 

Up to file-list examples/django_roa_client/models.py:

2
2
from django.db import models
3
3
from django.template.defaultfilters import slugify
4
4
5
from django_roa import Model, Manager
5
from django_roa import Model
6
6
7
7
class RemotePage(Model):
8
8
    title = models.CharField(max_length=50, blank=True, null=True)
@@ -62,7 +62,7 @@ class RemotePageWithCustomSlug(Model):
62
62
    def __unicode__(self):
63
63
        return u'%s (%s)' % (self.title, self.id)
64
64
65
    def save(self, force_insert=False, force_update=False):
65
    def save(self, force_insert=False, force_update=False, using=None):
66
66
        if not self.slug:
67
67
            self.slug = slugify(self.title)
68
68
        super(RemotePageWithCustomSlug, self).save(force_insert, force_update)
@@ -82,7 +82,7 @@ class RemotePageWithOverriddenUrls(Model
82
82
    def __unicode__(self):
83
83
        return u'%s (%s)' % (self.title, self.id)
84
84
85
    def save(self, force_insert=False, force_update=False):
85
    def save(self, force_insert=False, force_update=False, using=None):
86
86
        if not self.slug:
87
87
            self.slug = slugify(self.title)
88
88
        super(RemotePageWithOverriddenUrls, self).save(force_insert, force_update)

Up to file-list examples/django_roa_client/tests.py:

@@ -485,7 +485,9 @@ class ROAAdminTests(ROAUserTestCase):
485
485
        response = c.login(username=u'bob', password=u'secret')
486
486
        self.assertEqual(response, True)
487
487
        response = c.get('/admin/')
488
        self.assertEqual(repr(response.context[-1]["user"]), '<User: bob>')
488
        # ._wrapped necessary because we compare string, comparison should 
489
        # work with User.objects.get(username="bob") but slower...
490
        self.assertEqual(repr(response.context[-1]["user"]._wrapped), '<User: bob>')
489
491
        response = c.get('/admin/django_roa_client/remotepage/')
490
492
        self.assertEqual(response.status_code, 200)
491
493
        self.assertEqual(repr(response.context[-1]["cl"].result_list), '[<RemotePage: Still another remote page (4)>, <RemotePage: Yet another remote page (3)>]')