2

Situation: Have an existing mysql database with some data. For this example, I only use two fields; id and subject. id is defined as Integer with the *auto_increment* option, while subject is just a normal varchar. The code:

Model:

class AList(models.Model):
    id=models.AutoField(primary_key=True, db_column='ID')
    subject=models.CharField(max_length=200, db_column='SUBJECT')
    class Meta:
        db_table = u'alist'

Form:

class AForm(ModelForm):
    class Meta:
        model=AList

View:

def alistForm(request,a_id=None):
    if a_id:
        a=AList.objects.get(id=a_id)
        form=AForm(instance=a)
    else:
        form=AForm(request.POST or None)
    return render_to_response('aform.html',{'form':form},context_instance=RequestContext(request)

def alistPost(request):
    form=AForm(request.POST or None)
    if form.is_valid():
        form.save()

Description of the problem: When the form sends new data to the alistPost-function, the form.save() inserts a new record as it should. But when I edit an already existing record, that too is inserted as a new record... and not updated as it should do.

Trying to change the id from AutoField to an IntegerField changes the behavior: Modifying a record makes form.save() to modify the existing one, while trying to insert a new record it fails because it does not have an id.

Question: Do I manually have to get a new ID-value from the database and force Django to use it for this new record, or is there a way to make Django automagically figure out if it should use INSERT or UPDATE?

Eigir
  • 1,969
  • 2
  • 14
  • 19

3 Answers3

4

dragoon is on the right track, but your comment makes a valid point. A better pattern is like this:

if a_id:
    a = AList.objects.get(id=a_id)
else:
    a = AList()
if request.POST:
    form = AForm(request.POST, instance=a)
    ...
else:
    form = AForm(instance=a)
Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • Thank you for the answer. I changed the pattern to be like the one you provided, but it still does not work as intended. I have also changed the id in the model to be an IntergerField(primary_key=True). This because AutoField always produced a new entry in the database. The way I move on now, is to check if the id field from the form exists, and manually get the max value from the database... and manually set the new one to a higher value (I know... possible race condition). Don't like this approach much, but have been banging my head into this problem for too long now... :) – Eigir Oct 24 '11 at 14:36
  • `form = AForm(request.POST, instance=a)` did the trick for me. – webtweakers Oct 09 '13 at 15:38
1

This is what I did:

def someView(request,id=None):
   instance = form = None

   ...
      ...
   elif request.method == 'POST':

        if id != None:
            instance = SomeClass.objects.get(id=id)
            form = AForm(request.POST,instance=instance)
        else:
            form = AForm(request.POST) 

        if form.is_valid():

           instance = form.save()
           if not id:
               return redirect('edit',id=instance.id)
        else
            ...
        ...

urls:

url(r'^addedit/$', 'som.views.someView', name='edit'),
url(r'^addedit/(?P<id>.*)/$', 'som.views.someView', name='edit'),

so after the object is created at /addedit/, user is redirected to /addedit/1234/

hovno
  • 31
  • 2
0

The problem is that you doing a POST in a separate function where you don't supply instance argument to the form.

Try to merge functions into one like this:

def alistForm(request, pk)
    alist = get_object_or_404(AList, pk=pk)
    form = AFrom(request.POST or None, instance=alist)
    if request.method == 'POST':
        if form.is_valid():
            form.save()
    ...
dragoon
  • 5,601
  • 5
  • 37
  • 55
  • Thank you for the answer. Have tried to rewrite it to be more like your example, but there is a problem with the pk-part. With no pk, it fails with a 404. The point is that a call with no pk, there is no instance to pass, and the form should be empty. With a pk, the form should be populated with the existing data, and a submit should update the database. And this is where it fails. Using AutoField in the model, insert the modified data as new, while using an IntegerField updates it correctly (but fails to insert new data due to missing pk (primary_key=True might be a problem here?). – Eigir Oct 19 '11 at 12:33