Sebastian
Sebastian

Reputation: 2570

Update state of form with button django

Every row of the table has a button with the pk of the element. Using the button should fill the form with the states of the entry.

I think I have a problem with the renderer, as it clears my form but I'm not sure how to fix this. I would like to achieve this without the use of AJAX if possible.

HTML:

        <form action="" method="POST">
          {% csrf_token %}
          <input type="hidden" name="pk" value="{{ post.pk }}">
          <input class="btn btn-default btn-danger" name="update" type="submit" value="Ändern"/>
        </form>

views.py:

from django.shortcuts import render
from django.utils import timezone
from django.contrib.auth.decorators import login_required
from django.http import HttpResponseRedirect

from .forms import NameForm
from .models import Eintrag

@login_required()
def get_name(request):


    # if this is a POST request we need to process the form data
    if request.method == 'POST' and 'add' in request.POST:
        # create a form instance and populate it with data from the request:
        form = NameForm(request.POST)
        # check whether it's valid:
        if form.is_valid():
            #Eintrag.objects.filter(Name=request.user).delete()
            eintrag = form.save(commit=False)
            # process the data in form.cleaned_data as required
            # ...
            # redirect to a new URL:
            eintrag.Name = request.user  # Set the user object here
            eintrag.pub_date = timezone.now()  # Set the user object here
            eintrag.save()

            return HttpResponseRedirect(request.path)  # generate an empty form

    if request.method == 'POST' and 'delete' in request.POST:
        Eintrag.objects.filter(id=request.POST['pk']).delete()
        return HttpResponseRedirect(request.path)

    if request.method == 'POST' and 'update' in request.POST:
        form = NameForm()
        form.fields['Anmeldung'] = Eintrag.objects.get(id=request.POST['pk']).Anmeldung
        form.fields['Essen'] = Eintrag.objects.get(id=request.POST['pk']).Essen
        form.fields['Email'] = Eintrag.objects.get(id=request.POST['pk']).Email
        return HttpResponseRedirect(request.path) # this emptys my form
        #posts = Eintrag.objects.filter(Name=request.user) 
        #return render(request, 'form/name.html', {'form': form, 'posts': posts}) # I get an AttributError with this 

    # if a GET (or any other method) we'll create a blank form
    else:
        form = NameForm()

    posts = Eintrag.objects.filter(Name=request.user)
    return render(request, 'form/name.html', {'form': form, 'posts': posts})

forms.py

from django import forms
from .models import Eintrag

class NameForm(forms.ModelForm):

    class Meta:
            model = Eintrag
            fields = ['Anmeldung', 'Essen','Email']

models.py

from django.db import models

Anmeldung = (
    ('1', 'Ja'),
    ('2', 'Nein'),
    ('3', 'Noch nicht entschieden'),
)

Essen = (
    ('1', 'Fleisch'),
    ('2', 'Fisch'),
    ('3', 'Vegetarisch'),
)

class Eintrag(models.Model):
    Name = models.CharField(max_length=200)
    Anmeldung = models.CharField(
        max_length=2,
        choices=Anmeldung)
    Essen = models.CharField(
        max_length=2,
        choices=Essen)
    Email = models.EmailField()
    pub_date = models.DateTimeField('date published')

With my try to just create posts and render after the POST, I'm getting some error. like this:

Exception Type: AttributeError
Exception Value:    
'str' object has no attribute 'get_bound_field'

Thanks for your help.

form.['field'] should set the current state of the form to the selected data, I tried form['field'].initial too.

Full Traceback with:

posts = Eintrag.objects.filter(Name=request.user) 
            return render(request, 'form/name.html', {'form': form, 'posts': posts})

Template error:
In template C:\Users\basti\Desktop\hochzeit\form\templates\form\name.html, error at line 35
   'str' object has no attribute 'get_bound_field'
   25 :         <div class="row">
   26 : 
   27 : 
   28 :           <div class="col-sm-10">
   29 : 
   30 :             <div class='container-fluid'>
   31 :             <br><br>
   32 : 
   33 : <form action="" method="post">
   34 :     {% csrf_token %}
   35 :      {{ form }} 
   36 :     <input type="submit" name="add" value="Update" />
   37 : </form>
   38 : 
   39 : {% include "form/post_list.html" %}
   40 : 
   41 :             </div>
   42 :           </div>
   43 :     </div>
   44 : 
   45 : </body>

Traceback:

File "C:\Python35\lib\site-packages\django\core\handlers\exception.py" in inner
  35.             response = get_response(request)

File "C:\Python35\lib\site-packages\django\core\handlers\base.py" in _get_response
  128.                 response = self.process_exception_by_middleware(e, request)

File "C:\Python35\lib\site-packages\django\core\handlers\base.py" in _get_response
  126.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "C:\Python35\lib\site-packages\django\contrib\auth\decorators.py" in _wrapped_view
  21.                 return view_func(request, *args, **kwargs)

File "C:\Users\basti\Desktop\hochzeit\form\views.py" in get_name
  41.         return render(request, 'form/name.html', {'form': form, 'posts': posts})

File "C:\Python35\lib\site-packages\django\shortcuts.py" in render
  36.     content = loader.render_to_string(template_name, context, request, using=using)

File "C:\Python35\lib\site-packages\django\template\loader.py" in render_to_string
  62.     return template.render(context, request)

File "C:\Python35\lib\site-packages\django\template\backends\django.py" in render
  61.             return self.template.render(context)

File "C:\Python35\lib\site-packages\django\template\base.py" in render
  175.                     return self._render(context)

File "C:\Python35\lib\site-packages\django\template\base.py" in _render
  167.         return self.nodelist.render(context)

File "C:\Python35\lib\site-packages\django\template\base.py" in render
  943.                 bit = node.render_annotated(context)

File "C:\Python35\lib\site-packages\django\template\base.py" in render_annotated
  910.             return self.render(context)

File "C:\Python35\lib\site-packages\django\template\base.py" in render
  999.         return render_value_in_context(output, context)

File "C:\Python35\lib\site-packages\django\template\base.py" in render_value_in_context
  978.             value = str(value)

File "C:\Python35\lib\site-packages\django\utils\html.py" in <lambda>
  380.     klass.__str__ = lambda self: mark_safe(klass_str(self))

File "C:\Python35\lib\site-packages\django\forms\forms.py" in __str__
  136.         return self.as_table()

File "C:\Python35\lib\site-packages\django\forms\forms.py" in as_table
  279.             errors_on_separate_row=False)

File "C:\Python35\lib\site-packages\django\forms\forms.py" in _html_output
  201.             bf = self[name]

File "C:\Python35\lib\site-packages\django\forms\forms.py" in __getitem__
  167.             self._bound_fields_cache[name] = field.get_bound_field(self, name)

Exception Type: AttributeError at /form/
Exception Value: 'str' object has no attribute 'get_bound_field'

Upvotes: 1

Views: 1097

Answers (1)

Daniel Roseman
Daniel Roseman

Reputation: 599600

As I said in the comment, that's not how you assign values to a form field. What you've done is to completely replace the field object in the form's dictionary with the value from the model, which isn't at all what you want to do.

With a normal form, you could pass this data in via the initial dict when creating the form instance. But this is a ModelForm, which is specifically designed to take values from models; you should just pass the model instance itself via the instance argument:

eintrag = Eintrag.objects.get(id=request.POST['pk'])
form = NameForm(instance=eintrag)
posts = Eintrag.objects.filter(Name=request.user) 
return render(request, 'form/name.html', {'form': form, 'posts': posts})

Upvotes: 1

Related Questions