django custom manager with filter parameter

15,281

I'd simplify it:

class CurrentManager(models.Manager):
    def current(self, my_date):
        return super(CurrentManager, self).get_query_set().filter(valid_from__lte=my_date) 

and then use it like this:

a = A.objects.get(id=a_id)
my_date = request.user.get_profile().my_date
b_objects = a.b_set.objects.current(my_date)

and then just pass a to the template as the filtered objects accessing them using this:

{% for b in b_objects %}

Hope this helps!

Edit (by requestor):

I had to adjust it as follows to get it working:

a = A.objects.get(id=a_id)
my_date = request.user.get_profile().my_date
b_objects = a.b_set.current(my_date)

This threw an error: "'RelatedManager' object has no attribute 'objects'"

a.b_set.objects.current(my_date)
Share:
15,281

Related videos on Youtube

szeta
Author by

szeta

Updated on June 17, 2022

Comments

  • szeta
    szeta about 2 years

    I would like to add a custom manager which can be called from a template, but does not affect the entire model (e.g. admin views) and which listens to a parameter set in the request (user_profile).

    The following is what I have so far:

    models.py:

    class CurrentQuerySet(models.query.QuerySet):
        def current(self):
                return self.filter(id=1) ## this simplified filter test works..
    class CurrentManager(models.Manager):
        use_for_related_fields = True
        def get_query_set(self):
                return CurrentQuerySet(self.model)
        def current(self, *args, **kwargs):
                return self.get_query_set().current(*args, **kwargs)
    

    For model B is defined:

        objects = CurrentManager()
    

    The template calls:

    {% for b in a.b_set.current %}
    

    But as soon as I try to pass a parameter to that filter (in this case a date stored on the user-profile) the method does not return any results.

    e.g.:

    models.py

    class CurrentQuerySet(models.query.QuerySet):
        def current(self,my_date): 
                return self.filter(valid_from__lte=my_date) 
    

    showA.html

    {% for b in a.b_set.current(request.user.get_profile.my_date) %}
    

    Instead of passing the parameter from the template, I have also tried to set this in the view.py

    @login_required
    def showA(request,a_id):
        my_date = request.user.get_profile().my_date
        a = A.objects.get(id=a_id)
        t = loader.get_template('myapp/showA.html')
        c = RequestContext(request,{'a':a,'my_date':my_date,})
        return HttpResponse(t.render(c))
    

    Which part am I missing (or misunderstanding) here?

    Thanks

    R

    Edit

    Here the models. As mentioned, in this example it's a simple 1:n relationship, but can also be m:n in other cases.

    class A(models.Model):
        #objects = CurrentManager()
        a = models.CharField(max_length=200)
        description = models.TextField(null=True,blank=True)
        valid_from = models.DateField('valid from')
        valid_to = models.DateField('valid to',null=True,blank=True)
        def __unicode__(self):
                return self.a
    
    class B(models.Model):
        #objects = models.Manager()
        objects = CurrentManager()
        a = models.ForeignKey(A)
        b = models.CharField(max_length=200)
        screenshot = models.ManyToManyField("Screenshot",through="ScreenshotToB")
        description = models.TextField(null=True,blank=True)
        valid_from = models.DateField('valid from')
        valid_to = models.DateField('valid to',null=True,blank=True)
        def __unicode__(self):
                return self.b
    

    Edit-2

    The accepted answer works for at least one relationship.
    In case of a more nested data model, this method seems not to deliver the expected results:

    models.py

    class C(models.Model):
        objects = CurrentManager()
        b = models.ForeignKey(A)
        c = models.CharField(max_length=200)
        description = models.TextField(null=True,blank=True)
        valid_from = models.DateField('valid from')
        valid_to = models.DateField('valid to',null=True,blank=True)
        def __unicode__(self):
                return self.c
    

    views.py

    @login_required
    def showA(request,a_id):
        a = A.objects.get(id=a_id)
        my_date = request.user.get_profile().my_date
        b_objects = a.b_set.current(my_date)
        c_objects = b_objects.c_set.current(my_date)
        t = loader.get_template('controltool2/showA.html')
        c = RequestContext(request,{'a':a,'b_objects':b_objects,'c_objects':c_objects,})
        return HttpResponse(t.render(c))
    

    This returns the error: 'QuerySet' object has no attribute 'c_set'.

  • szeta
    szeta almost 11 years
    Hi, thanks for your simplification. Maybe I should have been more clear, that there are two models involved, Model A and Model B (in this case 1:n). That's why I do a a = A.objects.get(id=a_id) and then {% for b in a.b_set.current %}. How would I apply this? In the view I'm only touching A so far.