Contacts.models.DoesNotExist: Contact matching query does not exist


#1

The solution to this particular error has been evading me for about three days now. I have been searching on google and stackoverflow etc but have not found anything that answers my problem.

def contact_detail(request, slug):
    # grab the object...
    contact = Contact.objects.get(slug=slug)
    # and pass to the template
    return render(request, 'contact_detail', {'contact': contact, })

The error seems to point to line above with the contact variable. The error occurs as soon as I click ‘create contact’ in index.html. I’d really appreciate some assistance. I am thinking it is a stupid simple mistake I have made. I’m not even sure how to do a slug with this or even whether I need one.

The model this relates to is as follows:-

class Contact(models.Model):
    firstname = models.CharField(max_length = 50, blank = False, null = False)
    surname = models.CharField(max_length = 50, blank = False, null = False)
    address1 = models.CharField(max_length = 50, blank = False, null = False)
    address2 = models.CharField(max_length = 50, blank = True, null = True)
    address3 = models.CharField(max_length = 50, blank = True, null = True)
    town = models.CharField(max_length = 50, blank = False, null = False)
    county = models.CharField(max_length = 50, blank = False, null = False)
    country = models.CharField(max_length = 50, blank = True, null = True)
    postcode = models.CharField(max_length = 10, blank = False, null = False)
    telephone = models.CharField(max_length = 30, blank = True, null = True)
    mobile = models.CharField(max_length = 30, blank = False, null = False)
    email = models.EmailField(null = True, blank = True)
    birthday = models.DateField(blank = True, null = True)
    birthdaycardsent = models.BooleanField(default = False)
    xmascardreceived = models.BooleanField(default = False)
    xmascardsent = models.BooleanField(default = False)
    notes = models.TextField(null = True, blank = True)
    slug = models.SlugField(unique = True)
    
    def __str__ (self):
        return self.firstname + ' ' + self.surname
    
    def get_absolute_url(self):
        return "/contacts/%s/" % self.slug    

urls:-

from django.conf import settings
from django.conf.urls import url, include
from django.contrib import admin
from django.views.generic import TemplateView
from contacts import views


urlpatterns = [
    url(r'^$', views.index, name = 'home'),
    
    url(r'^contacts/$', views.contacts, name = 'contacts'),
    url(r'^about/$', TemplateView.as_view(template_name='about.html'), name='about'),
    url(r'^contact/$', TemplateView.as_view(template_name='contact.html'), name='contact'),    
    url(r'^contacts/(?P<slug>[-\w]+)/$', views.contact_detail, name='contact_detail'),
    url(r'^contacts/(?P<slug>[-\w]+)/edit/$', views.edit_contact, name='edit_contact'),
    url(r'^contacts/create_contact/$', views.create_contact, name='create_contact'),
    url(r'^admin/', admin.site.urls),
]

index.html:-

{% extends 'base.html' %}

{% block title %}
    Homepage - {{ block.super }}
{% endblock title %}

{% block content %}
    {% for contact in contacts %}
        <h2><a href="{% url 'contact_detail' slug=contact.slug %}">
            {{ contact.firstname }} {{ contact.surname }}
        </a></h2>
        <p>{{ contact.birthday }}</p>
    {% endfor %}
    <a href="{% url 'create_contact' %}">Create new contact</a>
    <a href="{% url 'home' %}">Home</a>

{% endblock content %}

#2

Are you importing Contact from your models at the top of your views.py?

Something like this: from collection.models import Contact


#3

Hi yes I am. Here’s the top part of my views:-

from django.shortcuts import render, redirect
from contacts.models import Contact
from contacts.forms import ContactForm
from django.template.loader import get_template
from django.template.defaultfilters import slugify
from django.template import Context
from django.http import Http404
from django.conf import settings

I really cannot see what is going on here…


#4

Here’s my project tree. I think I have it correctly although something is nagging at me.


#5

The thjng is that there are multiple created for this mistake, anoither being:-

p, li { white-space: pre-wrap; }

File “/home/david/webprjs/housekeeperprj/venv/lib/python2.7/site-packages/django/core/handlers/base.py”, line 185, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File “/home/david/webprjs/housekeeperprj/housekeeper/contacts/views.py”, line 52, in contact_detail
contact = Contact.objects.get(slug=slug)

These seem to be the failing views. What I do not understand is why when I am creating a new contact, it should not even be failing on the contact_detail view.

def contact_detail(request, slug):
    # grab the object...
    contact = Contact.objects.get(slug=slug)
    # and pass to the template
    return render(request, 'contact_detail', {'contact': contact, })


def create_contact(request):
    form_class = ContactForm
    # if we're coming from a submitted form, do this
    if request.method == 'POST':
        # grab the data from the submitted form and apply to
        # the form
        form = form_class(request.POST)
        if form.is_valid():
            # create an instance but do not save yet
            contact = form.save(commit=False)
            # set the additional details
            #contact.user = request.user
            slugstr = "%s %s" % (contact.firstname, contact.surname)
            contact.slug = slugify(slugstr)
            # save the object
            contact.save()
            # redirect to our newly created contact
            return redirect('contact_detail', slug=contact.slug)
    # otherwise just create the form
    else:
        form = form_class()
    
    return render(request, 'contacts/create_contact.html', {'form': form, })

#6

So this’ll fail if you search for a slug that doesn’t exist (server error like the one you got). The slug you’re searching for, is there a corresponding object in your database? Does it work when you search for a slug that does exist?


#7

Ok, I have some success. It has something to do with urls.py. I have found that even though I am calling the url to create_contact, it was somehow trying to display contact_detail instead.
So, I have changed the order of urls.py and moved the one for create_contact above the other contact related urls and I don’t know what but it works:-

from django.conf import settings
from django.conf.urls import url, include
from django.contrib import admin
from django.views.generic import TemplateView
from contacts import views


urlpatterns = [
    url(r'^$', views.index, name = 'home'),
    
    url(r'^contacts/$', views.contacts, name = 'contacts'),
    url(r'^about/$', TemplateView.as_view(template_name='about.html'), name='about'),
    url(r'^contacts/create_contact/$', views.create_contact, name='create_contact'),
    url(r'^contact/$', TemplateView.as_view(template_name='contact.html'), name='contact'),    
    url(r'^contacts/(?P<slug>[-\w]+)/$', views.contact_detail, name='contact_detail'),
    url(r'^contacts/(?P<slug>[-\w]+)/edit/$', views.edit_contact, name='edit_contact'),
    url(r'^admin/', admin.site.urls),
]

#8

Ah yeah that’s right — it was looking for an object with the slug of “create_contact” first. :) Good investigating, sorry I wasn’t much help!


#9

Oh you were definitely of help though Tracy, Although I was able to resolve it, I am still perplexed as to why changing the order of the url patterns should resolve the problem. The patterns are all different and no two should ever match a given url, so that would suggest to me that there is an error elsewhere causing this. Or am I wrong?

It throws this error as the last in a string of errors…

File "/home/david/webprjs/housekeeperprj/venv/lib/python2.7/site-packages/django/db/models/query.py", line 385, in get
  self.model._meta.object_name

contacts.models.DoesNotExist: Contact matching query does not exist.

Also prior to this there is this error:-

File "/home/david/webprjs/housekeeperprj/housekeeper/contacts/views.py", line 46, in contact_detail
  contact = Contact.objects.get(slug=slug)

And here is my view showing this line:-

def contact_detail(request, slug):
    # grab the object...
    contact = Contact.objects.get(slug=slug)
    ## and pass to the template
    return render(request, 'contacts/contact_detail.html', {'contact': contact, })

The only way that this can come about by creating a contact is from the redirect in my create_contact view but I have no idea why…

def create_contact(request):
    form_class = ContactForm
    # if we're coming from a submitted form, do this
    if request.method == 'POST':
        # grab the data from the submitted form and apply to
        # the form
        form = form_class(request.POST)
        if form.is_valid():
            # create an instance but do not save yet
            contact = form.save(commit=False)
            # set the additional details
            #contact.user = request.user
            contact.slug = slugify(' '.join([contact.firstname, contact.surname, ]))
            # save the object
            contact.save()
            # our new message!
            messages.success(request, 'Contact created successfully.')            
            # redirect to our newly created contact
            return redirect('contact_detail', slug=contact.slug)
    # otherwise just create the form
    else:
        form = form_class()
    
    return render(request, 'contacts/create_contact.html', {'form': form, })

This is what makes me believe changing the order of the urls isn’t the solution here and I still don’t understand why it does seem to fix it though.
Any ideas?


#10

Well first, changing the order mattered because it checks the URLs from top down.

If you navigated to /contacts/create_contact/ and your URLs had contacts/(?P<slug>[-\w]+)/ first, it would try to match create_contact to a slug and would never hit the following correct URL — which is why it’s throwing “slug does not exist” errors, because create_contact isn’t actually a slug.

So, if you have a URL with regex that says “hey match anything here and apply it to slug” (aka, (?P<slug>[-\w]+)/), you need to load the other URLs first so it checks those before doing the “match anything” URL.

I’m a little sick today, let me know if you need more clarification! :)


#11

Urls approach have confused me in the past, as I assumed Django would ‘understand’ which url regex is the best fit. But from reading it’s a simple algorithm that does an evaluation in the order they are defined. If a match happens, it short circuits any other url configuration and will invoke the view associated with it.

I am not sure this is a form of a ‘greedy regex’?

So, best practice would always mean to put your most restrictive urls up at the top, and least at the bottom.


#12

Yeah, it doesn’t “understand” best it, it simply goes top down finding something that fits. :)


#13

Thanks. I understand it working from the top down, but from what I could see, it was looking for a match that I think existed but it didn’t seem to find one, which led to my frustration. However, by hook or by crook, I have somehow managed to resolve this problem. Unfortunately I’m not sure what I did to correct the error, which is almost equally frustrating as I am not able to learn from my mistakes lol.
Thanks again.

David