开发者

Break up several actions into multiple view functions

开发者 https://www.devze.com 2023-03-13 13:33 出处:网络
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.

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="del开发者_开发问答ete_{{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.


A few ideas:

  1. You could split your one big html form element into chunks
  2. You could use AJAX submit handler to change URL based on pressed submit button
  3. You could do what user Cerales suggested, but instead of redirecting which loses POST data you could just call add_school() and other methods, possibly having also dictionary map of actions mapped to their handlers: action_map = {'Add School': add_school, ...} - this would eliminate chain of conditions
  4. You could use class-based view which would be basically a class-based version of #3. Django docs for generic class-based views are here

I can elaborate on any of those ideas if you will.

--

EDIT:

Answering your question from comments:

from django.views.generic.base import View
class MySchoolView(View):
    def post(self, request, *kargs, **kwargs):
        if 'Add School' in request.POST:
            return self.add_school(request, *kargs, **kwargs)
        # (...)
    def add_school(self, request, *kargs, **kwargs):
        # (...)

Then in urls.py:

(r'^schools/add/$', MySchoolView.as_view())

Note that the above is not tested so might require some tweaks to work. View class source code is here.


There's a couple of ways you could do this.

This could be a part of your view:

if request.method == 'POST':

    if 'Add School' in request.POST.values():
        return HttpResponseRedirect('/add_school/')

Then this could be part of another view, corresponding with the /add_school/ url:

def add_school(request):        
        if request.method=='POST':
        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')
0

精彩评论

暂无评论...
验证码 换一张
取 消