0

I create several forms to edit some records. When I save the form, I can see in the database that the application update the record and insert one or two record more.

All the forms that I use to update record have this weird behavior. I don't know if the error is in the form definition or in the view definition.

Model

class DetalleRecepcion(models.Model):
    id_proveedor = models.ForeignKey(Proveedor,db_column='id_proveedor',primary_key=True,      verbose_name='Proveedor')
    anio = models.IntegerField( null=False)
    mes = models.IntegerField(verbose_name='Mes')
    fecha_recepcion = models.DateField(verbose_name='Fecha Recepcion')
    usuario = models.CharField(max_length=15, blank=True)
    num_archivos = models.IntegerField(primary_key=True, verbose_name='No de archivos')

    class Meta:
        managed = False
        db_table = 'mpc_detalle_recepcion'

View

@login_required(login_url='/login/')
def DetRecView(request):
    idp = request.GET.get('i')
    anio = request.GET.get('a')
    mes = request.GET.get('m')
    if request.method == 'POST':
       r = DetalleRecepcion.objects.get(id_proveedor=idp,anio=anio,mes=mes)
       form = DetRecForm(request.POST or None, instance =r)
       if form.is_valid():
          form.save()
          return HttpResponse('<script type="text/javascript">window.close()</script>')
    else:
       r = DetalleRecepcion.objects.get(id_proveedor=idp,anio=anio,mes=mes)
       r.usuario = request.user
       form = DetRecForm(instance=r)

    return render_to_response('detrec.html',
                              {'form':form},
                              context_instance=RequestContext(request))

Form

class DetRecForm(forms.ModelForm):
      fecha_recepcion = forms.DateField(widget=DateInput(),)
      def __init__(self,*args,**kwargs):
          super(DetRecForm,self).__init__(*args,**kwargs)
          self.helper = FormHelper(self)
          self.helper.layout = Layout(
           Field('id_proveedor',
                 'anio',
                 'mes',
                 'usuario',
                 readonly = True
                 ),
           Fieldset('',
                    'fecha_recepcion',
                    'num_archivos',
                    Submit('save','Grabar'),
                    HTML('<a class="btn btn-danger" id="cerrar">Cancelar</a>')
                    )
          )
      class Meta:
          model = DetalleRecepcion

I am using a legacy database, I check the constrains, procedure, triggers of the database and everything look fine. Beside the table don't use any procedure function etc.

And only when I update or insert from the application I can see this behavior.

UPDATE

urls.py
urlpatterns = patterns('',
    url(r'^recepcion/$','prov.views.DetRecView',name='recepcion'),
    url(r'^newdetrec/$','prov.views.NewDetRecView',name='newdetrec'),
    url(r'^master/$','prov.views.NewMasterView',name='master'),
    url(r'^conci/$', 'prov.views.ConciView',name='conci'),
    url(r'^carga/$', 'prov.views.CargaView',name='carga'),
    url(r'^gencert/$', 'prov.views.GenCertView',name='gencert'),
    url(r'^entcert/$', 'prov.views.EntCertView',name='entcert'),
    url(r'^aceptacert/$', 'prov.views.AceptaCertView',name='aceptacert'),
    url(r'^envconci/$', 'prov.views.EnvConciView',name='envconci'),
)

My create view (for the same model)

  @login_required(login_url='/login/')
    @permission_required('prov.views.configView',login_url='/login/')
    def NewDetRecView(request):
        form = NewDetRecForm(request.POST or None)
        if request.method == 'POST':
           idp = request.POST['id_proveedor']
           a = request.POST['anio']
           m = request.POST['mes']
           id = Proveedor.objects.get(id_proveedor=idp)
           obj,created = DetalleRecepcion.objects.get_or_create(id_proveedor=id,anio=a,mes=m)
           obj.save()
           return HttpResponseRedirect('/monitor/')

           if not created:
              obj.id_proveedor = id
              obj.anio = a
              obj.mes = m
              obj.save()
              return HttpResponseRedirect('/monitor/')
        return render_to_response('newdetrec.html',
                              {'form':form})

My form class to create new records:

class NewDetRecForm(forms.ModelForm):
      def __init__(self,*args,**kwargs):
       super(NewDetRecForm,self).__init__(*args,**kwargs)
       self.helper = FormHelper(self)
       self.helper.layout.append(Submit('save','Grabar'))
       self.helper.layout = Layout(
        Fieldset('',
                 'id_proveedor',
                 'anio',
                 'mes',
                 Submit('save','Grabar'),
                )
       )
      def clean(self):
        cleaned_data = super(NewDetRecForm, self).clean()

        id_proveedor = self.cleaned_data['id_proveedor']
        #num_archivos = self.cleaned_data['num_archivos']
        anio = self.cleaned_data['anio']
        mes = self.cleaned_data['mes']

        qs = self.Meta.model.objects.filter(id_proveedor=id_proveedor, anio=anio, mes=mes)
        if self.instance:
            qs = qs.exclude(pk = self.instance.pk)
        if qs.count() > 0:
            raise forms.ValidationError(u'Registro ya existente')

        return cleaned_data
      class Meta:
        model = DetalleRecepcion

DetRecForm is for update

DetRecView is for update

NewDetRecForm is for create

NewDetRecView is for create

UPDATE 2

javascript function to pass parameters

<script type="text/javascript">
  $(document).ready ( function () {
    $(document).on ("click", "#recepcion", function (event) {
        event.preventDefault();
        var tbl = document.getElementById("myTable");
        var idpro = $(this).parents('tr:first').find('td:first').text();
        var anio = $(this).closest('tr').children(":eq(1)").text();
        var mes = $(this).closest('tr').children(":eq(2)").text();
        var argu = "?i="+idpro+"&a="+anio+"&m="+mes;
        //window.location = "/recepcion/"+argu;
        var url = "/recepcion/"+argu;
        window.open(url,'_blank')
    });
});
</script>

I know this isn't the right way to pass parameters to the templates. I am start learning AJAX to pass the data, but meanwhile I use this horrible function

Joseleg
  • 393
  • 9
  • 35

1 Answers1

0
url(r'^recepcion/add/$','prov.views.DetRecView',name='recepcion_add'),  # create object
url(r'^recepcion/edit/(?P<pk>\d+)/$','prov.views.DetRecView',name='recepcion_edit'),  # update object

Lets look at your condition in the view function: if request.method=='POST' better use if request.POST,

So when you have else - it means request.GET you get an instance of DetalleRecepcion (read instance as object of some class) and pass it to your ModelForm. It is update object approach (but you use this to create object), and provided query must give one object (unique).

If you want use this view to create and update you have to change your urls (smth like I did above) and you have to define condition: if request.kwargs.get('pk') you're going to update object else you're going to create object.

Main difference that if it is update case you have to provide instance to your form r = DetalleRecepcion.objects.get(pk=request.kwargs['pk']), so DetRecForm(instance=r) (whenrequest.GET) and form = DetRecForm(request.POST, instance =r) (whenrequest.POST).

If you want provide some initial data to your form (when request.GET) use DetRecForm(initial = {'id_proveedor': idp, 'anio': anio, 'mes': mes, 'usuario': request.user})

madzohan
  • 11,488
  • 9
  • 40
  • 67
  • I use this view only to update records and i create a different view to create records. The users must update the records, but only the admin(Me) can create new records. I will update the post and you can check my create view. Creating or updating I get duplicated rows inserted. And THANKS man. – Joseleg Oct 27 '14 at 17:22
  • You should update your code in question due recommendation above (and why you use `get_or_create` if you have a form `form.save()`). – madzohan Oct 27 '14 at 17:44
  • I will follow your recomendations and I am using get_or_create because I get the exception that the id_proveedor already exist. This is a legacy database and I get some issues for the primarys and foreigns keys. I will delete the .save() line – Joseleg Oct 27 '14 at 19:41
  • Sorry bother you, but I have a question for you @madzohan. How can I pass parameters from a HTML table to a template. I think my problem is the way how I pass the parameters to the edit form template. At fisrt I get a lot of error trying to pass values from a html table rendered with django-tables2 to the edit forms. I finally make this with a horrible javascript function. I paste the function I am using to pass the parameters in the post. – Joseleg Oct 27 '14 at 20:25
  • django-tables2 render queryset as html table on your template, so all rendered data you have first in your view queryset. So I don't understand what you mean "How can I pass parameters from a HTML table to a template" because it is already there. What exactly do you want to do? – madzohan Oct 27 '14 at 22:12
  • Take some cell values and pass it as parameter to the edit form. the table are rendered without any problem. In the tabla I have a dropdown button with several options, one options use the edit form and view definition. I need to take the value of the first three columns(id_proveedor,anio,mes) and send it as parameters to the edit form of the model DetalleRecepcion. You can see in the JS function I am not using get or post method to the parameters. In others words i can get the value from table cells that I need but I don't know how to pass it as arguments to the edit form – Joseleg Oct 27 '14 at 22:31
  • Calling `window.open(url,'_blank')` you create `GET` request to your view. It will be better if you wrap your `td`s (in each `tr`) by `form` and each `td` value by `input`, in this case you can submit form (it will be faster then js). But for that you need override default django-tables2 template. – madzohan Oct 27 '14 at 22:52
  • How can only convert to input text the first three columns – Joseleg Oct 28 '14 at 16:19
  • override default django-tables2 template and set it on your view `table = table_class(filter_obj.qs, template='common/tables/my_table.html') context['table'] = table` – madzohan Oct 28 '14 at 17:40
  • also you can customise rendering of model field by `TemplateColumn` – madzohan Oct 28 '14 at 17:46
  • Thanks, But I don't know why my view definition update all the records who had the same id_proveedor. I try using `unique_together ("id_proveedor,"anio,"mes")` and the always update all the records with the same id_proveedor. – Joseleg Oct 28 '14 at 17:59