Skip to content

Commit 9918d10

Browse files
committed
Merge pull request saxix#61 from ticosax/get_fields-too-much
For ConditionalVersionField get_fields() returns too many fields
2 parents 18cf517 + 3fc07ac commit 9918d10

File tree

3 files changed

+57
-4
lines changed

3 files changed

+57
-4
lines changed

src/concurrency/fields.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import absolute_import, unicode_literals
22

33
import copy
4+
import functools
45
import hashlib
56
import logging
67
import time
@@ -44,8 +45,8 @@ def class_prepared_concurrency_handler(sender, **kwargs):
4445

4546
if hasattr(sender, 'ConcurrencyMeta'):
4647
sender._concurrencymeta.enabled = getattr(sender.ConcurrencyMeta, 'enabled', True)
47-
check_fields = getattr(sender.ConcurrencyMeta, 'check_fields', [])
48-
ignore_fields = getattr(sender.ConcurrencyMeta, 'ignore_fields', [])
48+
check_fields = getattr(sender.ConcurrencyMeta, 'check_fields', None)
49+
ignore_fields = getattr(sender.ConcurrencyMeta, 'ignore_fields', None)
4950
if check_fields and ignore_fields:
5051
raise ValueError("Cannot set both 'check_fields' and 'ignore_fields'")
5152

@@ -310,6 +311,19 @@ def inner(self, force_insert=False, force_update=False, using=None, **kwargs):
310311
return update_wrapper(inner, func)
311312

312313

314+
def filter_fields(instance, field):
315+
if not field.concrete:
316+
# reverse relation
317+
return False
318+
if field.is_relation and field.related_model is None:
319+
# generic foreignkeys
320+
return False
321+
if field.many_to_many and instance.pk is None:
322+
# can't load remote object yet
323+
return False
324+
return True
325+
326+
313327
class ConditionalVersionField(AutoIncVersionField):
314328
def contribute_to_class(self, cls, name, virtual_only=False):
315329
super(ConditionalVersionField, self).contribute_to_class(cls, name, virtual_only)
@@ -333,10 +347,11 @@ def _get_hash(self, instance):
333347
check_fields = instance._concurrencymeta.check_fields
334348
ignore_fields = instance._concurrencymeta.ignore_fields
335349

350+
filter_ = functools.partial(filter_fields, instance)
336351
if check_fields is None and ignore_fields is None:
337-
fields = sorted([f.name for f in instance._meta.get_fields()])
352+
fields = sorted([f.name for f in filter(filter_, instance._meta.get_fields())])
338353
elif check_fields is None:
339-
fields = sorted([f.name for f in instance._meta.get_fields()
354+
fields = sorted([f.name for f in filter(filter_, instance._meta.get_fields())
340355
if f.name not in ignore_fields])
341356
else:
342357
fields = instance._concurrencymeta.check_fields
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# -*- coding: utf-8 -*-
2+
from __future__ import unicode_literals
3+
4+
from django.db import migrations, models
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
('demo', '0002_conditionalversionmodelwithoutmeta'),
11+
]
12+
13+
operations = [
14+
migrations.CreateModel(
15+
name='Anything',
16+
fields=[
17+
('id', models.AutoField(primary_key=True, verbose_name='ID', serialize=False, auto_created=True)),
18+
('name', models.CharField(max_length=10)),
19+
('a_relation', models.ForeignKey(to='demo.ConditionalVersionModelWithoutMeta')),
20+
],
21+
),
22+
migrations.AddField(
23+
model_name='conditionalversionmodelwithoutmeta',
24+
name='anythings',
25+
field=models.ManyToManyField(to='demo.Anything'),
26+
),
27+
]

tests/demoapp/demo/models.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
'ProxyModel', 'InheritedModel', 'CustomSaveModel',
1313
'ConcreteModel', 'TriggerConcurrentModel',
1414
'ConditionalVersionModelWithoutMeta',
15+
'Anything',
1516
]
1617

1718

@@ -213,6 +214,15 @@ class ConcurrencyMeta:
213214
check_fields = ['field1', 'field2', 'user']
214215

215216

217+
class Anything(models.Model):
218+
"""
219+
Will create a ManyToOneRel automatic field on
220+
ConditionalVersionModelWithoutMeta instances.
221+
"""
222+
name = models.CharField(max_length=10)
223+
a_relation = models.ForeignKey('demo.ConditionalVersionModelWithoutMeta')
224+
225+
216226
class ConditionalVersionModelWithoutMeta(models.Model):
217227
"""
218228
This model doesn't have ConcurrencyMeta defined.
@@ -222,6 +232,7 @@ class ConditionalVersionModelWithoutMeta(models.Model):
222232
field2 = models.CharField(max_length=30, blank=True, null=True, unique=True)
223233
field3 = models.CharField(max_length=30, blank=True, null=True, unique=True)
224234
user = models.ForeignKey(User, null=True)
235+
anythings = models.ManyToManyField(Anything)
225236

226237
class Meta:
227238
app_label = 'demo'

0 commit comments

Comments
 (0)