Django- NoReverseMatch

490 views Asked by At

I recently took over the development of a Python/ Django project, which uses Git as its version control, having not used either Python/ Django or Git much previously.

Having pushed some changes I made to the server, I found that although the changes I made had fixed the bug I was working on (the bug was to do with a date value not sticking/ being saved when the user selected a date in a form on one of the pages), another part of the project had somehow broken (a page titled 'AddsOmits')... but I'm not sure how, as I hadn't made any changes to that part.

The part that my fix actually broke may have come from an earlier version of the project, as I needed to checkout an earlier commit due to some errors I had while merging my changes to the master branch. So it may be that this is a bug which existed in an earlier commit.

I have now reverted the version on the live server to what it was before I uploaded the fix- so it is now in a working state, apart from the 'date' bug that I am currently working on.

On my local machine, I now have two branches: master, which is identical to the live version (i.e. where the 'date' bug still exists), and dateReceived (i.e. where I have fixed the 'date' bug, but where the 'AddsOmits' page is broken.

When I click the link that should take me to the 'AddsOmits' page in the browser (on dateReceived branch, I am presented with a page that says:

NoReverseMatch at costing/id/adds_omits

The 'Exception Value' in the error message is given as:

Reverse for 'export_csv' with arguments '('',)' and keyword arguments '{}' not found. 1 pattern(s) tried: [u'costing/(?P[0-9]+)/export-csv/$']

and the page says that there was an Error during template rendering, and:

In template /Users/.../costing/templates/costing/adds_omits.html, error at line 28 Reverse for 'export_csv' with arguments '('',)' and keyword arguments '{}' not found. 1 pattern(s) tried: [u'costing/(?P[0-9]+)/export-csv/$']

Line 28 of the template that it's complaining about is:

    <a class="button m-r-md" href="{% url 'costing:export_csv' budget.id %}">Export to Excel</a>

So it seems, if I understand correctly, that the error the browser is complaining about is something to do with the call to the view costing:export_csv, and that perhaps the URL patterns don't match...?

If I right click costing:export_csv in the template in my editor (Sublime), and select 'Goto Definition', I am taken to the view definition in costing/views.py:

import csv
from django.utils.encoding import smart_str
def export_csv(request, budget_id):
    budget = Budget.objects.get(id=budget_id)
    items = budget.budget_items.all()
    field_names = ('Build type', 'Build type detail', 'Item type client', 'Room', 'Name', 'Detail', 'Quantity', 'Unit', 'Cpu', 'Materials cost', 'Skill days', 'Labour days', 'Other unit', 'Other rate', 'Line margin', 'Total inc profit', 'Notes')
    fields = ([1, 'get_build_type_display'], 'build_type_detail', 'item_type_client', [1, 'get_room_name'], 'name', 'detail', 'quantity', 'unit', 'cpu', 'materials_cost', 'skill_days', 'labour_days', 'other_unit', 'other_rate', 'line_margin', 'total_inc_profit', 'notes')

    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename=Budget-'+budget.project.project_code+'.csv'
    writer = csv.writer(response, csv.excel)
    response.write(u'\ufeff'.encode('utf8')) # BOM (optional...Excel needs it to open UTF-8 file properly)
    writer.writerow([
        smart_str(u""+field_name) for field_name in field_names
    ])
    for obj in items:
        row = []
        for field in fields:
            if field[0] == 1:
                if hasattr(obj,field[1]): row += [smart_str(u""+plain_char(unicode(getattr(obj,field[1])() or '')))] # For methods such as get_build_type_display()
            elif hasattr(obj,field): row += [smart_str(u""+plain_char(unicode(getattr(obj,field) or '')))]
        writer.writerow(row)
    return response

The URL pattern used to call this view defined in costing/views.py is:

    url(r'^(?P<budget_id>[0-9]+)/export-csv/$', views.export_csv, name='export_csv'),

and as far as I can see, everything matches correctly (definition & calls, etc)...

What am I doing wrong here? The 'Exception Value' in the error message in the browser seems to indicate that I should be passing arguments somewhere that I'm not, or passing different ones/ not passing ones that I am...?

What is the reason for this exception, and how can I resolve it? Any help would be much appreciated.

Edit

The view for adds_omits is defined with:

def adds_omits(request, project_id):
    project = Project.objects.select_related('variations').prefetch_related('variations__addomit_set','variations__addomit_set__item').get(id=project_id)
    budget = get_current_budget(project_id)
    try: v = project.variations
    except ObjectDoesNotExist: v = Variations.objects.create(project=project)
    adds_omits = project.variations.addomit_set.select_related('item', 'item__project_room', 'item__project_room__room').all().order_by('item__build_type', 'item__build_type_detail', 'item__project_room', 'item__order', 'item__id') #Needs id to prevent other ordering within groups
    budget_items = BudgetItem.objects.select_related('addomit', 'addomit__variations', 'addomit__variations__project', 'project_room', 'project_room__room').filter(addomit__variations=v).order_by('build_type', 'build_type_detail', 'project_room', 'order', 'id') #Needs id to prevent other ordering within groups
    item_formset = BudgetItemFormsetLite(queryset=budget_items, form_kwargs={"ao":True,'project':project})
    ao_formset = AddOmitFormset(instance=v, queryset=adds_omits)
    formsets = zip(list(item_formset.forms), list(ao_formset.forms))

    for i_form in item_formset:
        for field in i_form.fields:
            if not field == 'id':
                i_form.fields[field].widget.attrs['readonly'] = True
                i_form.fields[field].widget.attrs['disabled'] = True

    #Used to create new add omits
    print 'Item form ini'
    item_form = BudgetItemForm(project=project, template=1)
    var_type_form = AoVariationTypeForm()

    context = {
        'project': project,
        'formsets': formsets,
        'ao_formset': ao_formset,
        'item_formset': item_formset,
        'var_type_form': var_type_form,
        'item_form': item_form,
        'widths': budget_item_column_widths[4:], #First column is add/delete options to allow for forloop count offset
        'options_width': "5em",  #First column is add/delete options to allow for forloop count offset
        'widths_ao': add_omit_column_widths,
        'widths_item': budget_item_column_widths, #First column is add/delete options to allow for forloop count offset
        'labour_rate': labour_day_rate,
        'skill_rate': skill_day_rate,

    }

    return render(request, 'costing/adds_omits.html', context)
1

There are 1 answers

3
Alasdair On BEST ANSWER

The error is in the view for costing/id/adds_omits, which you haven't shown.

The arguments '('',) suggests that you are not including budget in the template context, therefore budget.id in {% url 'costing:export_csv' budget.id %} is evaluated as an empty string ''.