Skip to content

Commit 10284ab

Browse files
committed
Support other lookups on ModelInstance
This makes `ModelInstance` accept a keyword argument `lookup` (that defaults to 'pk') which allows to specify which lookup to use on the given `QuerySet`.
1 parent ef543b5 commit 10284ab

File tree

4 files changed

+48
-15
lines changed

4 files changed

+48
-15
lines changed

djclick/params.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55

66
class ModelInstance(click.ParamType):
7-
def __init__(self, qs):
7+
def __init__(self, qs, lookup='pk'):
88
from django.db import models
99

1010
if isinstance(qs, type) and issubclass(qs, models.Model):
@@ -14,13 +14,17 @@ def __init__(self, qs):
1414
qs.model._meta.app_label,
1515
qs.model.__name__,
1616
)
17+
self.lookup = lookup
1718

1819
def convert(self, value, param, ctx):
20+
if value is None:
21+
return super(ModelInstance, self).convert(value, param, ctx)
1922
try:
20-
return self.qs.get(pk=value)
23+
return self.qs.get(**{self.lookup: value})
2124
except ObjectDoesNotExist:
2225
pass
2326
# call `fail` outside of exception context to avoid nested exception
2427
# handling on Python 3
25-
msg = 'could not find {} with pk={}'.format(self.name, value)
28+
msg = 'could not find {s.name} with {s.lookup}={value}'.format(
29+
s=self, value=value)
2630
self.fail(msg, param, ctx)

djclick/test/test_params.py

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import pytest
21
from click.exceptions import BadParameter
2+
import pytest
33

44
from djclick import params
55

@@ -18,17 +18,37 @@ def test_modelinstance_init():
1818

1919

2020
@pytest.mark.django_db
21-
def test_convert_ok(call_command):
21+
@pytest.mark.parametrize(
22+
('arg', 'value'),
23+
(
24+
('--pk', '99'),
25+
('--slug', 'test'),
26+
('--endswith', 'st'),
27+
)
28+
)
29+
def test_convert_ok(call_command, arg, value):
2230
from testapp.models import DummyModel
2331

24-
DummyModel.objects.create()
25-
assert call_command('modelcmd', '1').stdout == b'1'
32+
DummyModel.objects.create(slug='test')
33+
expected = b'<DummyModel: 1>'
34+
35+
assert call_command('modelcmd', '--pk', '1').stdout == expected
36+
assert call_command('modelcmd', '--slug', 'test').stdout == expected
37+
assert call_command('modelcmd', '--endswith', 'test').stdout == expected
2638

2739

2840
@pytest.mark.django_db
29-
def test_convert_fail(call_command):
41+
@pytest.mark.parametrize(
42+
('args', 'error_message'),
43+
(
44+
(('--pk', '99'), "pk=99"),
45+
(('--slug', 'doesnotexist'), "slug=doesnotexist"),
46+
)
47+
)
48+
def test_convert_fail(call_command, args, error_message):
3049
with pytest.raises(BadParameter) as e:
31-
call_command('modelcmd', '999')
50+
call_command('modelcmd', *args)
3251
# Use `.endswith()` because of differences between CPython and pypy
33-
assert str(e).endswith('BadParameter: could not find '
34-
'testapp.DummyModel with pk=999')
52+
assert str(e).endswith(
53+
'BadParameter: could not find testapp.DummyModel with {}'.format(
54+
error_message))

djclick/test/testprj/testapp/management/commands/modelcmd.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,14 @@
55

66

77
@click.command()
8-
@click.argument('instance', type=ModelInstance(DummyModel.objects.all()))
9-
def command(instance):
10-
# Just print some things which shall not be found in the output
11-
click.echo(instance, nl=False)
8+
@click.option('--pk', type=ModelInstance(DummyModel))
9+
@click.option('--slug', type=ModelInstance(DummyModel, lookup="slug"))
10+
@click.option('--endswith', type=ModelInstance(DummyModel,
11+
lookup="slug__endswith"))
12+
def command(pk, slug, endswith):
13+
if pk:
14+
click.echo(repr(pk), nl=False)
15+
if slug:
16+
click.echo(repr(slug), nl=False)
17+
if endswith:
18+
click.echo(repr(endswith), nl=False)

djclick/test/testprj/testapp/models.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,7 @@
66

77
@python_2_unicode_compatible
88
class DummyModel(models.Model):
9+
slug = models.CharField(max_length=50)
10+
911
def __str__(self):
1012
return str(self.id)

0 commit comments

Comments
 (0)