field choices() as queryset?

3,638 views
Skip to first unread message

galago

unread,
Feb 24, 2011, 6:53:03 AM2/24/11
to django...@googlegroups.com
I need to make a form, which have 1 select and 1 text input. Select must be taken from database.
model looks like this:
class Province(models.Model):
    name = models.CharField(max_length=30)
    slug = models.SlugField(max_length=30)

    def __unicode__(self):
        return self.name

It's rows to this are added only by admin, but all users can see it in forms.
I want to make a ModelForm from that. I made something like this:
class ProvinceForm(ModelForm):
    class Meta:
        CHOICES = Province.objects.all()

        model = Province
        fields = ('name',)
        widgets = {
            'name': Select(choices=CHOICES),
        }

but it doesn't work. The select tag is not displayed in html. What did I wrong?

Mike Ramirez

unread,
Feb 24, 2011, 7:10:17 AM2/24/11
to django...@googlegroups.com

I haven't done this one in a while, but you need to make the CHOICES a tuple or a list[1], not a queryset (unless there has been changes in this specific area).

something like this:

def make_choices():

choices = []

for item in Province.objects.all()

choices.append((item.name, item.name))

return choices

# your form stuff

...

widgets = { 'name': Select(choices=make_choices()), }

The first value is the value stored, the second one is the human readable form in the tuple.

Mike

[1] http://docs.djangoproject.com/en/1.2/ref/models/fields/#field-choices

--

Banacek's Eighteenth Polish Proverb:

The hippo has no sting, but the wise man would rather be sat upon

by the bee.

galago

unread,
Feb 24, 2011, 7:21:46 AM2/24/11
to django...@googlegroups.com
Thanks, that's the way I'll do it:)
But now I have 1 more problem. In ModelForm I want to get some data about user from DB. I nedd to filter user provinces. How canI call the user  id in my query? I pass request.user as form instance in view: form = ProvinceForm(instance=request.user)
How to read that inside my form? self.instance.id doesn't work:/

Chris Matthews

unread,
Feb 24, 2011, 7:29:54 AM2/24/11
to django...@googlegroups.com

Typo

choices.append((item.name, item.name))

should be

choices.append((item.id, item.name))

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To post to this group, send email to django...@googlegroups.com.
To unsubscribe from this group, send email to django-users...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-users?hl=en.

Mike Ramirez

unread,
Feb 24, 2011, 7:31:30 AM2/24/11
to django...@googlegroups.com

Whats the forms __init__ method look like?

Mike

--

Q: What's hard going in and soft and sticky coming out?

A: Chewing gum.

galago

unread,
Feb 24, 2011, 8:00:23 AM2/24/11
to django...@googlegroups.com
I made it that way but i get empty select list

class ProvinceForm(ModelForm):
    def __init__(self, *args, **kwargs):
        super(ProvinceForm, self).__init__(*args, **kwargs)
        user_provinces = UserProvince.objects.select_related().filter(user__exact=self.instance.id).values_list('province')
        self.fields['name'].choices = Province.objects.exclude(id__in=user_provinces).values_list('id', 'name')

    class Meta:
        model = Province
        fields = ('name',)
        widgets = {
            'name': Select(),
        }

galago

unread,
Feb 24, 2011, 8:07:35 AM2/24/11
to django...@googlegroups.com
hmm, that solutoin works great:)
class ProvinceForm(ModelForm):
    def __init__(self, *args, **kwargs):
        super(ProvinceForm, self).__init__(*args, **kwargs)
        user_provinces = UserProvince.objects.select_related().filter(user__exact=self.instance.id).values_list('province')
        self.fields['name'].queryset = Province.objects.exclude(id__in=user_provinces).only('id', 'name')

    name = forms.ModelChoiceField(queryset=None, empty_label=None)

    class Meta:

Mike Ramirez

unread,
Feb 24, 2011, 8:07:56 AM2/24/11
to django...@googlegroups.com

for self.instance, you'll wnat to do something like this:

self.instance = kwargs.pop('instance')

or add:

def __init__(self, instance, *args, **kwargs):

self.instance = instance

as for the blank items, verify your query works as expected. After that I'm not sure.

Mike

--

If I felt any more SOPHISTICATED I would DIE of EMBARRASSMENT!

Tom Evans

unread,
Feb 24, 2011, 8:15:09 AM2/24/11
to django...@googlegroups.com
On Thu, Feb 24, 2011 at 1:07 PM, Mike Ramirez <gufy...@gmail.com> wrote:
> On Thursday, February 24, 2011 05:00:23 am galago wrote:
>> class ProvinceForm(ModelForm):
>
>> def __init__(self, *args, **kwargs):
>> <snip>

>
> for self.instance, you'll wnat to do something like this:
>
> self.instance = kwargs.pop('instance')
>
> or add:
>
> def __init__(self, instance, *args, **kwargs):
>
> self.instance = instance
>
> as for the blank items, verify your query works as expected. After that I'm
> not sure.
>
> Mike
>

Er, no, he should be calling the super-class (ModelForm) constructor,
which would correctly handle instance being in kwargs and set
self.instance - which the OP is doing. Cargo cult programming is bad.

Cheers

Tom

Mike Ramirez

unread,
Feb 24, 2011, 8:22:21 AM2/24/11
to django...@googlegroups.com

On Thursday, February 24, 2011 05:15:09 am Tom Evans wrote:

> Cargo cult programming is bad.

>

> Cheers

>

> Tom

Not going to really argue the point, it's valid, but it could be based on habits taught by others, mentors...

Mike

--

Never, ever lie to someone you love unless you're absolutely sure they'll

never find out the truth.

galago

unread,
Feb 24, 2011, 9:17:34 AM2/24/11
to django...@googlegroups.com
Now I have some strange thing. I display my form, send post and try to save it. But it doesn't save:/
Here's my code:
model:
class UserProvince(models.Model):
    user = models.ForeignKey(User)
    province = models.ForeignKey(Province)

    class Meta:
        unique_together = (('user', 'province'), )

    def __unicode__(self):
        return self.user.username + '/' + self.province.name

form:
class ProvinceForm(ModelForm):
    def __init__(self, *args, **kwargs):
        super(ProvinceForm, self).__init__(*args, **kwargs)
        user_provinces = UserProvince.objects.select_related().filter(user__exact=self.instance.id).values_list('province')
        self.fields['province'].queryset = Province.objects.exclude(id__in=user_provinces).only('id', 'name')

    province = forms.ModelChoiceField(queryset=None, empty_label=None)
    range_type = forms.CharField(initial='province', widget=forms.HiddenInput())

    class Meta:
        model = UserProvince
        fields = ('province',)

view:
if request.POST:
        form = ProvinceForm(request.POST, instance=request.user)
        if form.is_valid():
            obj = form.save(commit=False)
            obj.user = request.user
            obj.save()

form is valid, but save method makes no effect :/

Tom Evans

unread,
Feb 24, 2011, 9:29:03 AM2/24/11
to django...@googlegroups.com

Your form is a ModelForm for a UserProvince model, and you are passing
in an django.contrib.auth.User instance as the instance. This is
wrong!
If you are editing an existing UserProvince instance, then pass that
object to the form as the instance. If you are creating a new
UserProvince instance, then do not pass in instance.

If you want your form to automatically associate the user with the
instance, then that user should be passed to the form's constructor,
and override save() to associate it with the instance, eg:

class FooForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user')
super(FooForm, self).__init__(*args, **kwargs)
def save(commit=False):
foo = super(FooForm, self).save(commit=False)
if not foo.user:
foo.user = self.user
if commit:
foo.save()
return foo

Cheers

Tom

galago

unread,
Feb 24, 2011, 9:53:23 AM2/24/11
to django...@googlegroups.com
I think it works. Thanks. What I did:
changed the form cal in view:
form_provinces_to_add = ProvinceForm(request.POST, user=request.user)

changed a form a little:
class ProvinceForm(ModelForm):
    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop('user')
        super(ProvinceForm, self).__init__(*args, **kwargs)
        user_provinces = UserProvince.objects.select_related().filter(user__exact=self.user.id).values_list('province')
        self.fields['province'].queryset = Province.objects.exclude(id__in=user_provinces).only('id', 'name')

    province = forms.ModelChoiceField(queryset=None, empty_label=None, label=_(u'Wybierz województwo'))
    range_type = forms.CharField(initial='province', widget=forms.HiddenInput())

    class Meta:
        model = UserProvince
        fields = ('province',)

    def save(self, commit=True):
        foo = super(ProvinceForm, self).save(commit=False)
        foo.user = self.user
        if commit:
            foo.save()
        return foo

The line You wrote: if not foo.user:  makes an error when posting:
No exception supplied
Exception Type:
      DoesNotExist
\django\db\models\fields\related.py in __get__, line 301
commit True
self <apps.accounts.forms.ProvinceForm object at 0x030F1F30>
foo Error in formatting:
Reply all
Reply to author
Forward
0 new messages