1
\$\begingroup\$

I have one large view function where a user can Add, Edit, Delete, and Update his education. I am currently doing this all in one view because I haven't yet learned how to split up views by function. Here is what I currently have --

I have a single URL pointing to the view --

url(r'^profile/edit/education/$', 'views.edit_education', name='edit_education')

Here is my model/modelform --

class Education(models.Model):
    school = models.CharField(max_length=100)
    class_year = models.IntegerField(max_length=4, blank=True, null=True, choices=YEAR)
    degree = models.CharField(max_length=100, blank=True)
    user = models.ForeignKey('UserProfile')

class EducationForm(ModelForm):    
    class Meta:
        model = Education
        exclude = ('user',)    

Here is my view --

@login_required
def edit_education(request, edit=0):
    """
    In the edit profile page, allows a user to edit his education
    and add multiple school entries.
     """
    profile = request.user.get_profile()
    education = profile.education_set.order_by('-class_year')   # for the template. display all eduation entries
# unindented for legibility
if request.method == 'POST':

    if 'Add School' in request.POST.values():
        form = EducationForm(data=request.POST, request=request) # passing request to form to do validation based on request.user
        if form.is_valid():
            new_education = form.save(commit=False)
            new_education.user = profile
            new_education.save()
            return redirect('edit_education')

    if 'Delete' in request.POST.values():
        for education_id in [key[7:] for key, value in request.POST.iteritems() if key.startswith('delete')]:
            Education.objects.get(id=education_id).delete()
            return redirect('edit_education')

    if 'Edit' in request.POST.values():
        for education_id in [key[5:] for key, value in request.POST.iteritems() if value == 'Edit' and key.startswith('edit')]:
            edit = 1   
            school_object = Education.objects.get(id = education_id)
            form = EducationForm(instance = school_object, request=request)
        return render_to_response('userprofile/edit_education.html', {'form': form, 'education':education, 'edit': edit, 'education_id': education_id}, context_instance=RequestContext(request))

    if 'Cancel' in request.POST.values():
        return redirect('edit_education')  

    if 'Save Changes' in request.POST.values():
        form = EducationForm(request.POST, request=request, edit=1)
        if form.is_valid():
            Education.objects.get(id=request.POST['education_id']).delete() # is there a way to update instead of delete and re-add?
            new_education = form.save(commit=False)
            new_education.user = profile
            new_education.save()
            return redirect('edit_education')
else:
    form = EducationForm(request=request)
return render_to_response('userprofile/edit_education.html', {'form': form, 'education': education, }, context_instance=RequestContext(request))

And finally, my template --

<h3>Edit education info for {{user.get_full_name}}</h3> 

<form action="." method="post"> {% csrf_token %}
{% if education %}
{% for education in education %}
    <p><b>{{ education.school }}</b> {% if education.class_year %}{{ education.class_year|shorten_year}}, {% endif %} {{ education.degree}} 
    <input type="submit" name="edit_{{education.id}}" value='Edit' />
    <input type="submit" name="delete_{{education.id}}" value="Delete" /></p>
{% endfor %}
{% endif %}

<table> 
<input type="hidden" name="education_id" value="{{education_id}}" />
<tr><td>School:</td><td>{{form.school}}{{form.school.errors}}</td></tr>
<tr><td>Class Year</td><td>{{form.class_year}}{{form.class_year.errors}}</td></tr>
<tr><td>Degree:</td><td>{{form.degree}}{{form.degree.errors}}</td></tr>
<tr>{{form.non_field_errors}}</tr>
</table>

{% if not edit %}
    <p><input type="submit" name="add" value="Add School" ></p>
{% else %}
    <p><input type="submit" name="save" value="Save Changes" >
    <input type="submit" name="cancel" value="Cancel" ></p>
{% endif %}
</form>

And the end is here. How would I separate one of these actions in the view into separate view functions using separate URLs? One or two examples would be more than enough. Thank you very much for your help.

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Simple way to split it up by block logic (create, edit, remove or else)

# app/views.py
def create_edit(request, id=None):
    # if id: we should edit instance
    #else: we shoud create new instance
    return ...

def delete(request, id):
    # remove instance
    return ...

# app/url.py
from django.conf.urls.defaults import *

urlpatterns = patterns('app.views',
    url('^add/$', 'create_edit', name='school-add'),
    url('^(\d+)/edit/$', 'create_edit', name='school-edit'),
    url('^(\d+)/delete/$', 'create_edit', name='school-delete'),
)

# url.py
from django.conf.urls.defaults import *

urlpatterns = patterns('',
    ('^schools/', include('app.urls')),
)

Also I saw you edit method and I think it's wrong. you have to look in Django docs

this will be better then removing and adding new object.

inst = Edu.objects.get(id=id)
form = EduForm(request.POST, intance=inst)
if form.is_valid():
   form.save()

Edit and Delete submit buttons you should change to <a href="{% url school-edit item.id %}">Edit</a> and <a href="{% url school-delete item.id %}">Delete</a> (or handle submit events with jQuery and redirect to correct URL)

Cancel button you can change to <a href="{% url %}">Cancel</a> and this would be better then you done with redirect().

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.