简体   繁体   中英

How do I filter values in a Django 1.7 form using ModelForm?

I am trying to use the ModelForm to add my data. It is working well, except that the ForeignKey dropdown list is showing all values and I only want it to display the values that a pertinent for the logged in user.

These are my models:

class productos(models.Model):
user        = models.ForeignKey(User)
secciones   = models.ForeignKey(secciones)
name        = models.CharField(max_length=50)
image       = models.ImageField(upload_to = 'productos')
precio      = models.DecimalField(max_digits=10, decimal_places=2, default=0.00)
descripcion = models.TextField(max_length=300, null=True,blank=True)

def save(self, *args, **kwargs):
    if not self.id:
        self.slug = slugify(self.name)
    super(productos, self).save(*args, **kwargs)

def __unicode__(self):
    return self.name
#####################################################################
class secciones(models.Model):
name = models.CharField(max_length=50)
user = models.ForeignKey(User)

def save(self, *args, **kwargs):
    if not self.id:
        self.slug = slugify(self.name)
    super(secciones, self).save(*args, **kwargs)

def __unicode__(self):
    return self.name

the form code:

class AgregarProducto(forms.ModelForm):
class Meta:
    model   = productos

And finally, the view code:

def agregar_producto(request):
if request.method == "POST":
    modelform = AgregarProducto(request.POST,request.FILES,user=request.user)
    print modelform
    if modelform.is_valid():
        modelform.save()

        return redirect("/editar-perfil/")
else:
    modelform = AgregarProducto()
return render(request, "home/AgregarProducto.html", {"form":modelform})

How do I get the form to display only the subset of secciones where secciones.user equals the logged in user?

AgregarProducto is as NewProduct right? I hope you tell us in english...

you need specific object from the secciones , an example is like this script below;

1. yourapp/models.py

class Secciones(models.Model):
    user = models.ForeignKey(User)
    name = models.CharField(max_length=50)

    def save(self, *args, **kwargs):
        if not self.id:
            self.slug = slugify(self.name)
        super(Secciones, self).save(*args, **kwargs)

    def __unicode__(self):
        return self.name


class Productos(models.Model):
    user        = models.ForeignKey(User)
    secciones   = models.ForeignKey(Secciones)
    name        = models.CharField(max_length=50)
    image       = models.ImageField(upload_to = 'productos/%Y/%m/%d/')
    precio      = models.DecimalField(max_digits=10, decimal_places=2, default=0.00)
    descripcion = models.TextField(max_length=300, null=True,blank=True)

    def save(self, *args, **kwargs):
        if not self.id:
            self.slug = slugify(self.name)
        super(Productos, self).save(*args, **kwargs)

    def __unicode__(self):
        return self.name

2. yourapp/forms.py

class AgregarProducto(forms.ModelForm):

  class Meta:
      model   = Productos
      fields = '__all__'
      exclude = ['user', 'secciones']

3. yourapp/views.py

from django.shortcuts import (render, redirect, get_object_or_404)
from django.contrib.auth.decorators import login_required
from django.core.urlresolvers import reverse

from yourapp.models import (Secciones, Productos)
from yourapp.forms import AgregarProducto


@login_required
def agregar_producto(request):
    """
    add new product view.
    """
    template_name = 'home/AgregarProducto.html'

    secciones = Secciones.objects.filter(user=request.user)
    if secciones.exists() == False:
        # do stuff, eg:
        return redirect('/error/page')

    if request.method == 'POST':
        form = AgregarProducto(request.POST, request.FILES)
        if form.is_valid():
            initial_object = form.save(commit=False)
            initial_object.user = request.user    # here you save current user logged in.

            # and also the `secciones` set single object,
            # because I see in your model is `ForeignKey`
            initial_object.secciones = secciones.first()
            initial_object.save()
            form.save()

            # you also can redirect to the saved object
            # an example;
            return redirect(reverse('edit_product_page', kwargs={'pk': initial_object.pk}))
        else:
            context = {'form': form, 'errors': form.errors}
            return render(request, template_name, context)
    else:
        form = AgregarProducto()
    return render(request, template_name, {'form': form})


@login_required
def edit_product(request, pk):
    """
    `productos` is from your model:productos
    I suggest you to use `uppercase` in your class name;
        eg: `Productors` but not `productos`

    :param `pk` is pk/id from instance object of `productos`
    """
    template_name = 'homee/edit_product.html'
    product = get_object_or_404(Productos, pk=pk)

    if request.method == 'POST':
        # instance the form from object of `product` above.
        form = AgregarProducto(request.POST, request.FILES, instance=product)
        if form.is_valid():
            initial_object = form.save(commit=False)
            initial_object.user = product.user # set from user creation
            initial_object.save()
            form.save()

            #do stuff

3. urls.py

from django.conf.urls import url

from yourapp.views import (agregar_producto, edit_product)

urlpatterns = [
    url(
        r'^product/new/$',
        agregar_producto, name='new_product_page'
    ),
    url(
        r'^product/(?P<pk>[-\d]+)/edit/$',
        edit_product, name='edit_product_page'
    ),
]

Hope it helpful..

It seem that what you want is to provide a filtered set of sections, so you can use the initial param when construction your form:

def agregar_producto(request):
    if request.method == "POST":
    modelform = AgregarProducto(request.POST,request.FILES,user=request.user)
    print modelform
    if modelform.is_valid():
        modelform.save()

        return redirect("/editar-perfil/")
else:
    modelform = AgregarProducto(initial={'user':request.user}) #pass in the authenticated user
return render(request, "home/AgregarProducto.html", {"form":modelform})

And then in your form:

class AgregarProducto(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(AgregarProducto, self).__init__(*args, **kwargs)

        if kwargs.get('initial'):
            user = kwargs.get('initial').get('user')
            if user:
                sections = secciones.objects.filter(user_id=user.id)
                self.fields['secciones'].choices = [(s.id, s.name) for s in sections]
                self.fields['client'].choices = [('', '---------')]+self.fields['client'].choices #this adds an "empty" option

    class Meta:
        model   = productos

This will only display the user's sections in the dropdown list, using the id as value and name as display.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM