honesty1997 honesty1997 - 8 months ago 57
Python Question

Failed with the get_object_or_404 django

This is the code:

>>> from shortener.models import KirrURL
>>> from django.shortcuts import get_object_or_404
>>> obj = get_object_or_404(KirrURL,shortcode='pric3e')

Traceback (most recent call last):File"/Users/phil/Desktop/django110/lib/python3.5/site
packages/django/shortcuts.py", line 85, in get_object_or_404
return queryset.get(*args, **kwargs)
File "/Users/phil/Desktop/django110/lib/python3.5/site-packages/django/db/models/query.py", line 385, in get
shortener.models.DoesNotExist: KirrURL matching query does not exist.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/Users/phil/Desktop/django110/lib/python3.5/site-packages/django/shortcuts.py", line 93, in get_object_or_404
raise Http404('No %s matches the given query.' % queryset.model._meta.object_name)
django.http.response.Http404: No KirrURL matches the given query.

>>> obj = KirrURL.objects.get(shortcode='pric3e')
>>> obj
<KirrURL: http://google.com>
>>> obj.id
>>> obj.url

I am practicing django model right now.The problem is when I used the get_object_or_404 trying to get the data which match the second key word argument it somehow failed.When I used get() method.It successes.I think I think I should get the same result here.

#Model Class
class KirrURLManager(models.Manager):
def all(self,*args,**kwargs):
qs = super(KirrURLManager,self).all(*args,**kwargs)
qs_main = qs.filter(active=False)
return qs_main

def refresh_shortcodes(self,items=None):
qs = KirrURL.objects.filter(id__gte=1)
if items is not None and isinstance(items,int):
qs = qs.order_by('-id')[:items]
for q in qs:
q.shortcode = create_shortcode(q)
class KirrURL(models.Model):
url = models.CharField(max_length=220,)
shortcode = models.CharField(max_length=SHORTCODE_MAX,unique=True,blank=True)
updated = models.DateTimeField(auto_now=True)
timestamp = models.DateTimeField(auto_now_add=True)
active = models.BooleanField(default=True)
objects = KirrURLManager()
some_random = KirrURLManager()
def save(self, *args, **kwargs):
if self.shortcode is None or self.shortcode == "":
self.shortcode = create_shortcode(self)
super(KirrURL, self).save(*args, **kwargs)
def __str__(self):
return str(self.url)
def __unicode__(self):
return str(self.url)

Answer Source

Your custom manager is producing inconsistent results because .all() is not always called. If you want this manager to always filter out specific instances, you should override get_queryset(). Be sure to include a default manager above your custom manager so you still have a way to access all instances in e.g. the admin.

class KirrURLManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(active=False)

class KirrURL(models.Model):
    objects = models.Manager() # default manager, put this one first
    custom = KirrURLManager()

Now KurrURL.objects.all() will return all instances (and get_object_or_404(KirrURL, shortcode='pric3e') will be able to find your instance), but you can access all inactive instances using KirrURL.custom.all().