Queryset in newforms

22 views
Skip to first unread message

Mario Gonzalez

unread,
Sep 27, 2007, 2:54:28 PM9/27/07
to Django developers
Hello:

I usually show forms using form_for_model(), however there's
something I think is missing. My model is something like:

class TransferFile(models.Model):
file = models.FileField(upload_to="/some/path/in/my/system/")
owner = models.ForeignKey(User, db_column="owner", db_index=True)
authorized_account = models.ManyToManyField(User,
related_name="authorized_account")

class Admin:
pass

class Meta:
permissions = (
('send_file', 'Can send files'),

In my DB I've got lot of users, each one with different groups and
permissions, and I don't want to show them in my form. So, I want to
pass a parameter in form_for_model() and I wrote a patch for that:

Index: models.py
===================================================================
--- models.py (revision 6426)
+++ models.py (working copy)
@@ -66,7 +66,7 @@
return save_instance(self, instance, fields, fail_message,
commit)
return save

-def form_for_model(model, form=BaseForm, fields=None,
formfield_callback=lambda f: f.formfield()):
+def form_for_model(model, form=BaseForm, fields=None, queryset=None,
formfield_callback=lambda f, **kwargs: f.formfield(**kwargs)):
"""
Returns a Form class for the given Django model class.

@@ -76,6 +76,7 @@
determining the formfield for a given database field. It's a
callable that
takes a database Field instance and returns a form Field
instance.
"""
+ from django.db.models.fields.related import ManyToManyField
opts = model._meta
field_list = []
for f in opts.fields + opts.many_to_many:
@@ -83,7 +84,10 @@
continue
if fields and not f.name in fields:
continue
- formfield = formfield_callback(f)
+ if isinstance(f, ManyToManyField) and queryset is not None:
+ formfield = formfield_callback(f, queryset=queryset)
+ else:
+ formfield = formfield_callback(f)
if formfield:
field_list.append((f.name, formfield))
base_fields = SortedDictFromList(field_list)

Have I got to create a ticket?

Regards.
Mario.-

Collin Grady

unread,
Sep 27, 2007, 4:25:04 PM9/27/07
to django-d...@googlegroups.com
Mario Gonzalez said the following:

> In my DB I've got lot of users, each one with different groups and
> permissions, and I don't want to show them in my form. So, I want to
> pass a parameter in form_for_model() and I wrote a patch for that:

Just make your own formfield_callback, that's what it's for :)

--
Collin Grady

A boss with no humor is like a job that's no fun.

Mario Gonzalez

unread,
Sep 27, 2007, 5:08:14 PM9/27/07
to Django developers
On 27 sep, 16:25, Collin Grady <cgr...@gmail.com> wrote:
> Mario Gonzalez said the following:
>
> > In my DB I've got lot of users, each one with different groups and
> > permissions, and I don't want to show them in my form. So, I want to
> > pass a parameter in form_for_model() and I wrote a patch for that:
>
> Just make your own formfield_callback, that's what it's for :)
>

I should have to write the all callback and I think that's not what
I want. My proposal is if you've got a special queryset, just pass it
trough form_for_model() method only. Then you haven't got to re-write
all over again.

Also, I don't want to change the field type, I just need a different
queryset. So far, Django not permit that(AFAIK) and I think this is
necessary.

>

Collin Grady

unread,
Sep 27, 2007, 6:03:00 PM9/27/07
to django-d...@googlegroups.com
Mario Gonzalez said the following:
> I should have to write the all callback and I think that's not what
> I want. My proposal is if you've got a special queryset, just pass it
> trough form_for_model() method only. Then you haven't got to re-write
> all over again.

Rewrite what all over? All you have to do is edit the generated field
for your m2m field and change the queryset/choices.

> Also, I don't want to change the field type, I just need a different
> queryset. So far, Django not permit that(AFAIK) and I think this is
> necessary.

But what if you have multiple m2ms to multiple model types? Your
proposal wouldn't support that - it would pass the same queryset to all
of them, which is invalid.

The proper solution for this is your own formfield_callback, not trying
to make form_for_* handle one narrow situation so that you don't have to
write one.

--
Collin Grady

Beam me up, Scotty! It ate my phaser!

Mario Gonzalez

unread,
Sep 27, 2007, 6:25:27 PM9/27/07
to Django developers
On 27 sep, 18:03, Collin Grady <cgr...@gmail.com> wrote:
> Mario Gonzalez said the following:
>
> > I should have to write the all callback and I think that's not what
> > I want. My proposal is if you've got a special queryset, just pass it
> > trough form_for_model() method only. Then you haven't got to re-write
> > all over again.
>
> Rewrite what all over? All you have to do is edit the generated field
> for your m2m field and change the queryset/choices.
>

I haven't seen this before, I'll try it but IMVHO it seems a hack
because you've got to generate a field and _then_ change the queryset.
I think the queryset must be defined once and not after.

> > Also, I don't want to change the field type, I just need a different
> > queryset. So far, Django not permit that(AFAIK) and I think this is
> > necessary.
>
> But what if you have multiple m2ms to multiple model types? Your
> proposal wouldn't support that - it would pass the same queryset to all
> of them, which is invalid.
>

Sure, the patch I sent was to explain my point only. I wanted to
know if the idea is good enough to use some time developing this.
Personally I think is a good idea.

>

Collin Grady

unread,
Sep 27, 2007, 6:36:35 PM9/27/07
to django-d...@googlegroups.com
Mario Gonzalez said the following:
> I haven't seen this before, I'll try it but IMVHO it seems a hack
> because you've got to generate a field and _then_ change the queryset.
> I think the queryset must be defined once and not after.

Actually, you don't - I just checked the formfield method of
ManyToManyField, and you can pass the queryset directly to that, so it
will use that when it generates the field instead of whatever it would
normally default to.

--
Collin Grady

Mario Gonzalez

unread,
Sep 28, 2007, 9:00:14 AM9/28/07
to Django developers
On 27 sep, 18:36, Collin Grady <cgr...@gmail.com> wrote:
>
> Actually, you don't - I just checked the formfield method of
> ManyToManyField, and you can pass the queryset directly to that, so it
> will use that when it generates the field instead of whatever it would
> normally default to.
>

Yes, ManyToMany is able to get the queryset and change it but
form_for_model doesn't

Collin, look: I deleted the file I modified (django.newforms.model.py)
and I did a svn update after, I used the project again and...

TypeError at /webapps/portal/archivos/
form_for_model() got an unexpected keyword argument 'queryset'
Request Method: GET
Request URL: http://127.0.0.1:8000/webapps/portal/archivos/
Exception Type: TypeError
Exception Value: form_for_model() got an unexpected keyword argument
'queryset'

In my views.py I've got:

some_queryset = A_Model.objects.filter(<some_condition>)
form_for_model(A_Model, queryset=some_queryset)

That's what I want to solve, give the opportunity to the programmer
to change the queryset easily when a form_for_model is needed but you
don't need the default queryset.

Collin Grady

unread,
Sep 28, 2007, 4:37:34 PM9/28/07
to django-d...@googlegroups.com
Mario Gonzalez said the following:
> That's what I want to solve, give the opportunity to the programmer
> to change the queryset easily when a form_for_model is needed but you
> don't need the default queryset.

I understand what you want, and you can do it with a formfield_callback!

You do /not/ need some new, custom addition to form_for_model for this
very, very narrow use-case.

###############

def my_callback(f, **kwargs):
if f.name == "districts":
kwargs['queryset'] = District.objects.filter(id__in=[1, 2, 3])
return f.formfield(**kwargs)

MyForm = forms.form_for_model(Region, formfield_callback=my_callback)
form = MyForm()

###############

And voila, now you have your queryset replaced. And this can be expanded
quite easily to support multiple m2m fields or foreignkeys or whatever
else you need to change, unlike your limited solution.

So as you can see, the ability to replace the queryset already exists,
and in a much better form :)

--
Collin Grady

The meta-Turing test counts a thing as intelligent if it seeks to
devise and apply Turing tests to objects of its own creation.
-- Lew Mammel, Jr.

Reply all
Reply to author
Forward
0 new messages