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.
| commit 131: | 3e613d59de36 |
| parent 130: | 2616a61bffb2 |
| branch: | default |
8 months ago
Changed (Δ2.5 KB):
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( |
|
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 |
|
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 |
|
|
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)>]') |
