Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[django] bestaand object updaten ipv nieuwe creeren via form

Pagina: 1
Acties:

  • Boudewijn
  • Registratie: Februari 2004
  • Niet online

Boudewijn

omdat het kan

Topicstarter
Hoihoi

offtopic:
Ik heb het idee dat ik tegen alle beginnersfouten oploop...

Ik heb de vrij bekende tango with django http://www.tangowithdjango.com/book/index.html manual gevolgd en heb die applicatie best wel uitgebreid.

Doelstelling die ik hierbij heb is het editten van objecten via modelforms mogelijk te maken.
Ik begrijp het volgende van hoe ik dit zou moeten bouwen:

Er is een paar scenario's mogelijk:
* Nieuw model (url = /jabberuser/edit , dit is een GET en geen instance en geen username parameter voor de view)
* Openen bestaand model (url = /jabberuser/edit/<username> , dit is een GET en geen instance, wel <username> als parameter)
* Opslaan bestaand model; dit is een POST.

Het DB-model werkt prima in mijn code; ik kan netjes modellen bekijken maar zodra ik een model wil editten krijg ik de opmerking dat ik een dubbele key heb; hij probeert dus te inserten ipv te updaten.

Mijn code:
Python:
1
2
3
4
5
6
7
8
9
10
class Organisation(models.Model):
    name                 = models.CharField(max_length=128, unique=True, primary_key=True)
    user_suffix         = models.CharField(max_length=64, unique=True)
    contact_person_name  = models.CharField(max_length=64)
    contact_person_tel   = models.CharField(max_length=64)
    contact_person_email = models.EmailField(max_length=64)

    # Override the __unicode__() method to return out something meaningful!
    def __unicode__(self):
        return self.name


Python:
1
2
3
4
5
6
7
8
9
10
forms.py:
class OrganisationForm(forms.ModelForm):
    name = forms.CharField(max_length=128, help_text="Organisation name")
    user_suffix = forms.CharField(max_length=128, help_text="Surffix (ie. test-test-nl)")
    contact_person_name = forms.CharField(max_length=10, help_text="Contact person (name)")
    contact_person_tel = forms.CharField(max_length=10, help_text="Contact person (tel)")
    contact_person_email = forms.CharField(max_length=10, help_text="Contact person (email)")
    
    class Meta:
            model = Organisation

Python:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
views.py:
def addorganisation(request,organisationname=None):
    # Get the context from the request.
    orgs=Organisation.objects.all()
    
    
    context = RequestContext(request)
    # A HTTP POST?
    
    org_instance = Organisation.objects.get(name=organisationname)
    form = OrganisationForm(request.POST,instance=org_instance)

    if request.method == 'POST':
        
        # Have we been provided with a valid form?
        if form.is_valid():
            # Save the new category to the database.
            form.save(commit=True)
            return HttpResponseRedirect('/organisationlist/')        
        else:
            # The supplied form contained errors - just print them to the terminal.
            print form.errors
   # else:
        # If the request was not a POST, display the form to enter details.
       #s form = OrganisationForm()    
        # Bad form (or form details), no form supplied...
        
        
        # Render the form with error messages (if any).
    return render_to_response('jabberadmin/add_organisation.html', {'form': form}, context)

En de relevate routes:
Python:
1
2
3
4
5
6
7
8
9
urls.py:


    url(r'^organisationlist/$', views.organisationlist),  
    url(r'^organisation/addorganisation/$', views.addorganisation),  
    url(r'^organisation/edit/(?P<organisationname>[a-zA-Z-]+)/$', views.addorganisation),   
    url(r'^organisation/(?P<organisationname>[a-zA-Z-]+)/$', views.organisation),
    url(r'^organisation/(?P<organisation>[a-zA-Z-]+)/users/$', views.jabberuserlist),
    url(r'^organisation/$', views.organisationlist),

Ik heb de view in zoverre werkend gehad (zonder instance, maar door gewoon onderstaand soort code te gebruiken) dat ik het model goed laat maar vervolgens zodra ik ga editten een create ipv update doe.
Python:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
views.py  (laadt models wel maar update niet)
     if organisationname != None:
         org=Organisation.objects.get(name=organisationname)#.get[0]
         form =OrganisationForm(instance=org)
        
     else:
         if request.method == 'POST':
             form = OrganisationForm(request.POST)
             # Have we been provided with a valid form?
             if form.is_valid():
                 # Save the new category to the database.
                 form.save(commit=True)
                 # Now call the index() view.
                 # The user will be shown the homepage.
                 return index(request)
              else:
                  # The supplied form contained errors - just print them to the terminal.
                 print form.errors
         else:
              # If the request was not a POST, display the form to enter details.
              form = OrganisationForm()    
            # Bad form (or form details), no form supplied...
        # Render the form with error messages (if any).
      return render_to_response('jabberadmin/add_organisation.html', {'form': form}, context)

Mijn punt met de dingen die ik met google heb gevonden (zoals : http://stackoverflow.com/...and-delete-data-in-django https://docs.djangoprojec.../topics/forms/modelforms/
http://stackoverflow.com/...l-data-using-django-forms) verzuip ik in de docs of is het een heel ander idee qua architectuur dan wat ik heb staan en ik wil liever niet de boel refactoren.


Alternatieve aanpak, voor een zelfde soort klasse en modelform:

Python:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def adduser(request, username=None):
    # Get the context from the request.
    context = RequestContext(request)
    # A HTTP POST?
    
    if username != None and request.method != 'POST':
        jabberuser=JabberUser.objects.get(name=username)#.get[0]
        form =JabberUserForm(instance=jabberuser)
        
    else:
        if request.method == 'POST':
            form = JabberUserForm(request.POST)
            # Have we been provided with a valid form?
            if form.is_valid():
                # Save the new category to the database.
                form.save(commit=True)
                # Now call the index() view.
                # The user will be shown the homepage.
                return index(request)
            else:
                # The supplied form contained errors - just print them to the terminal.
                print form.errors
        else:
            # If the request was not a POST, display the form to enter details.
            form = JabberUserForm()    
        # Bad form (or form details), no form supplied...
    # Render the form with error messages (if any).
    return render_to_response('jabberadmin/add_user.html', {'form': form, 'username':username}, context)

Ook hier create Django ipv update. Grmbl.

Kan iemand me een schopje de goede kant op geven?

[ Voor 11% gewijzigd door Boudewijn op 20-08-2014 02:16 ]


  • Merethil
  • Registratie: December 2008
  • Laatst online: 21:36
Kan je de specifieke error posten?

  • Boudewijn
  • Registratie: Februari 2004
  • Niet online

Boudewijn

omdat het kan

Topicstarter
Sure, komt ie.
Mijn huidige codebase:

De template (add_organisation.html)
Python:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
{% extends 'jabberadmin/base.html' %}

{% block body_block %}

        {% if organisationname %}
            <h1>Edit user {{ organisationname }}</h1>
        {% else %}
            <h1>New Organisation</h1>
        {% endif %}

        <form id="category_form" method="post" action="/jabberadmin/organisation/edit/{{ organisationname }}">
        
            {% csrf_token %}
            {% for hidden in form.hidden_fields %}
                {{ hidden }}
            {% endfor %}

            <table border="0">
            {% for field in form.visible_fields %}
                <tr>
                <td><font color="red">{{ field.errors }}</font>     </td>
                <td>{{ field.help_text }}   </td>
                <td>&nbsp&nbsp&nbsp{{ field }}      </td>
                </tr>
            {% endfor %}
            </table>



            <input type="submit" name="submit" value="Create Organisation" />
        </form>
{% endblock %}

De view:
Python:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def addorganisation(request,organisationname=None):
       # Get the context from the request.
    context = RequestContext(request)
    # A HTTP POST?
    
    if organisationname != None and request.method != 'POST':
        org_instance=Organisation.objects.get(name=organisationname)#.get[0]
        form =OrganisationForm(instance=org_instance)
        
    else:
        if request.method == 'POST':
            form = OrganisationForm(request.POST)
            # Have we been provided with a valid form?
            if form.is_valid():
                # Save the new category to the database.
                form.save(commit=True)
                # Now call the index() view.
                # The user will be shown the homepage.
                return index(request)
            else:
                # The supplied form contained errors - just print them to the terminal.
                print form.errors
        else:
            # If the request was not a POST, display the form to enter details.
            form = OrganisationForm()    
        # Bad form (or form details), no form supplied...
    # Render the form with error messages (if any).
    return render_to_response('jabberadmin/add_organisation.html', {'form': form, 'organisationname':organisationname}, context)



Hiermee probeer ik de code al te splitsen in een gewone get op een organisation (de if organisationname!= None and request.method != 'POST':), en vervolgens de POST van een organisatie waarbij je gaat valideren.


Goed wat doe ik:

1: Ik ga naar mijn edit page voor oragnisaties: http://localhost:8000/jabberadmin/organisation/edit/TestToko/ . Ik zie dat deze page gewoon klopt; de gegevens van TestToko zijn ingevuld.
2: Ik pas een telefoonnummer aan, maar laat de andere velden staan.
3: Submit het formulier.


Vervolgens zie ik de form helpers erroren en in de serverlog dit voorbij komen:
code:
1
<ul class="errorlist"><li>user_suffix<ul class="errorlist"><li>Organisation with this User suffix already exists.</li></ul></li><li>contact_person_email<ul class="errorlist"><li>Ensure this value has at most 10 characters (it has 15).</li></ul></li><li>name<ul class="errorlist"><li>Organisation with this Name already exists.</li></ul></li></ul>
De form error helpers geven die errors ook, te weten:
Organisation with this Name already exists.
Organisation with this User suffix already exists.
Ensure this value has at most 10 characters (it has 15).


Goed, die 10 karakters is een bugje mijnerzijds maar je ziet dat hij errort op de 2 velden die uniek moeten zijn in de DB:

Python:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Organisation(models.Model):
    name                 = models.CharField(max_length=128, unique=True, primary_key=True)
    user_suffix         = models.CharField(max_length=64, unique=True)
    contact_person_name  = models.CharField(max_length=64)
    contact_person_tel   = models.CharField(max_length=64)
    contact_person_email = models.EmailField(max_length=64)


en

class OrganisationForm(forms.ModelForm):
    name = forms.CharField(max_length=128, help_text="Organisation name")
    user_suffix = forms.CharField(max_length=128, help_text="Surffix (ie. test-test-nl)")
    contact_person_name = forms.CharField(max_length=10, help_text="Contact person (name)")
    contact_person_tel = forms.CharField(max_length=10, help_text="Contact person (tel)")
    contact_person_email = forms.CharField(max_length=128, help_text="Contact person (email)")
    
    # enabled=forms.BooleanField(widget=forms.HiddenInput, initial=True)
    #deleted=forms.BooleanField(widget=forms.HiddenInput, initial=True)

    #created_by=forms.ChoiceField(widget=forms.HiddenInput)
    #deleted_at = forms.CharField(widget=forms.HiddenInput)
    
    class Meta:
            model = Organisation

Ergo, hij probeert een nieuwe insert ipv een update.

[ Voor 9% gewijzigd door Boudewijn op 20-08-2014 02:17 ]


  • Boudewijn
  • Registratie: Februari 2004
  • Niet online

Boudewijn

omdat het kan

Topicstarter
Goed en dan vind je het zelf...geen idee hoe en wat. Was wat aan het googlen op "django update instead create" en dergelijke.

Code waar het wel mee werkt:
Python:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
def addorganisation(request,organisationname=None):
    # Get the context from the request.
    context = RequestContext(request)
    # A HTTP POST?
    org_instance=Organisation.objects.get(name=organisationname)#.get[0]
    form =OrganisationForm(instance=org_instance)

    if organisationname != None and request.method != 'POST':
        org_instance=Organisation.objects.get(name=organisationname)#.get[0]
        form =OrganisationForm(instance=org_instance)
        
    else:
        if request.method == 'POST':
            form = OrganisationForm(request.POST,instance=org_instance)
            # Have we been provided with a valid form?
            if form.is_valid():
                # Save the new category to the database.
                form.save(commit=True)
                # Now call the index() view.
                # The user will be shown the homepage.
                return render_to_response('jabberadmin/add_organisation.html', {'form': form, 'organisationname':organisationname}, context)

            else:
                # The supplied form contained errors - just print them to the terminal.
                print form.errors
        else:
            # If the request was not a POST, display the form to enter details.
            form = OrganisationForm()    
        # Bad form (or form details), no form supplied...
    # Render the form with error messages (if any).
    return render_to_response('jabberadmin/add_organisation.html', {'form': form, 'organisationname':organisationname}, context)

  • Roberttt
  • Registratie: Augustus 2005
  • Laatst online: 00:24
Zie django docs voor wat duiding: https://docs.djangoprojec...delforms/#the-save-method
A subclass of ModelForm can accept an existing model instance as the keyword argument instance; if this is supplied, save() will update that instance. If it’s not supplied, save() will create a new instance of the specified model
Lijkt me vrij duidelijk zo? ;)

  • Boudewijn
  • Registratie: Februari 2004
  • Niet online

Boudewijn

omdat het kan

Topicstarter
Zeker, je moet alleen wel weten waar te kijken.

Mijn huidige code is erg brak met die if-statements en blijkt ook niet lekker te werken als je een nieuw object aanmaakt (je hebt een post en een username dus hij gaat die in de DB opzoeken... en die bestaat niet). Allemaal ook wel weer te fixen maar ik heb het idee dat ik het wiel hier opnieuw uit zit te vinden.

Is er een pattern dat veel mensen voor zoiets gebruiken?

  • G70boX
  • Registratie: Juli 2004
  • Laatst online: 21:50
Ja, class based views (https://docs.djangoprojec...ed-views/generic-editing/, http://ccbv.co.uk/). Zijn zat tutorials over te vinden.

[ Voor 12% gewijzigd door G70boX op 20-08-2014 22:02 ]

Pagina: 1