About Django Narrowing Search

Asked 2 years ago, Updated 2 years ago, 111 views

I would like to implement a narrow search on the side menu of https://www.gumtree.com.au using Django.
For example, if you click Jobs on the global menu on this site, the side menu displays a subcategory of Jobs, which is a large category.Also, if you select a subcategory, the corresponding Post will be displayed in the center.
At this point, the URL is /BigCategory/ or /SmallCategory/.

Also, there is a category column like the one below.

Large Category
| Small Category
| - Small Category

Below this is

State
| Region
| Region

It is possible to narrow down the position.
If you select State, /BigCategory/State/ or /SmallCategory/State/ will display Post depending on the category you are currently selecting (large or smallCategory/State/
If you select Region, it will be /BigCategory/Region/ or /SmallCategory/Region/.

I'd like to implement these things.

The above URL is /Category/Location/, but when I thought about it myself and implemented it,

urls.py

 urlpatterns=[
    url(r'^(?P<cat>[-\w]+)/(?P<loc> [-\w]+)/$', views.loc_index, name='index',
    url(r'^(?P<cat>[-\w]+)/$', views.cat_index, name='index',
]

models.py

class BigCategory(models.Model):
    name=models.CharField(max_length=255)
    slug=models.SlugField()

    def__str__(self):
        return self.name

class SmallCategory (models.Model):
    parent=models.ForeignKey(BigCategory, related_name='children')
    name=models.CharField(max_length=255)
    slug=models.SlugField()

    def__str__(self):
        return self.name

class State (models.Model):
    name=models.CharField(max_length=255)
    slug=models.SlugField()

    def__str__(self):
        return self.name

Class Region (models.Model):
    parent=models.ForeignKey(State, related_name='children')
    name=models.CharField(max_length=255)
    slug=models.SlugField()

    def__str__(self):
        return self.name

class Post (models.Model):
    category=models.ForeignKey(SmallCategory)
    location=models.ForeignKey (Region)
    title=models.CharField(max_length=255)
    text=models.CharField(max_length=255)

    def__str__(self):
        return self.title

views.py

 from.models import BigCategory, SmallCategory, State, Region, Post

def cat_index(request, cat):

    if BigCategory.objects.filter(slug=cat):
        # cat==big
        big_cat = BigCategory.objects.get(slug=cat)
        states=State.objects.all()
        posts=Post.objects.filter(category__parent__slug=cat)
        c={'big_cat':big_cat,'states':states,'posts':posts}

    elif SmallCategory.objects.filter(slug=cat):
        # cat==small
        big_cat = BigCategory.objects.get(children__slug=cat)
        states=State.objects.all()
        posts=Post.objects.filter(category__slug=cat)
        c={'big_cat':big_cat,'states':states,'posts':posts}

    else:
        # raise404

    return render (request, 'classifieds/index.html', c)

def loc_index(request, cat, loc):

    if BigCategory.objects.filter(slug=cat):
        # cat==big
        big_cat = BigCategory.objects.get(slug=cat)
        selected_cat = 'big'

        if State.objects.filter(slug=loc):
            state=State.objects.get(slug=loc)
            posts=Post.objects.filter(category__parent__slug=cat, location_parent__slug=loc)
            c={'big_cat':big_cat,'selected_cat':selected_cat,'state':state,'posts':posts}

        elif Region.objects.filter(slug=loc):
            state=State.objects.get(children__slug=loc)
            posts=Post.objects.filter(category__parent__slug=cat, location__slug=loc)
            c={'big_cat':big_cat,'selected_cat':selected_cat,'state':state,'posts':posts}

        else:
            print('no location')

    elif SmallCategory.objects.filter(slug=cat):
        # cat==small
        big_cat = BigCategory.objects.get(children__slug=cat)
        selected_cat = 'small'
        small_cat_for_loc = SmallCategory.objects.get(slug=cat)

        if State.objects.filter(slug=loc):
            state=State.objects.get(slug=loc)
            posts=Post.objects.filter(category__slug=cat, location__parent__slug=loc)
            c={'big_cat':big_cat, 'small_cat_for_loc':small_cat_for_loc, 'state':state, 'posts':posts}

        elif Region.objects.filter(slug=loc):
            state=State.objects.get(children__slug=loc)
            posts=Post.objects.filter(category__slug=cat, location__slug=loc)
            c={'big_cat':big_cat, 'small_cat_for_loc':small_cat_for_loc, 'state':state, 'posts':posts}

        else:
            print('no location')

    else:
        # raise404

    return render (request, 'classifieds/index.html', c)

In the future, when I try to implement not only categories and locations, but also other options such as narrowing down, it will be a very long code that is hard to understand if I separate everything.

What I would like you to teach me is

URL How to separate URLs
If /BigCategory/SmallCategory/State/Region/, the implementation will be much easier than now, but if /BigCategory or SmallCategory/State or Region/, the URL will be shorter, so I would like to do this.Please tell me how to write an ideal view to achieve this

上記 I don't know Django yet, so I hit him hard, so please teach me how to review the entire code and the system itself.
For example, using custom template tags like this makes it easier.

Ideally, it is a reference site described at the beginning.
Please help me.

python django

2022-09-30 21:22

1 Answers

Considering the following, I think it can be implemented simply.
The differences between the models are as follows:

 1. Whether BigCategory and SmallCategory have parent or not
2. Whether State and Region have parent or not

Considering this difference, it would be good to combine each into a single model.

class Category (models.Model):
    # Have both BigCategory and SmallCategory roles
    parent=models.ForeignKey(Category, related_name='children', null=True, blank=True)
    name=models.CharField(max_length=255)
    slug=models.SlugField()

    def__str__(self):
        return self.name

class Location (models.Model):
    # Have both State and Region roles
    parent=models.ForeignKey (State, related_name='children', null=True, blank=True)
    name=models.CharField(max_length=255)
    slug=models.SlugField()

Data so far can be retrieved as follows:

#BigCateogry (no parent)
Category.objects.filter (parent__isnull=True)

# SmallCategory
Category.objects.filter (parent__isnull=False)

# State (no parent)
Location.objects.filter (parent__isnull=True)

# region
Location.objects.filter(parent__isnull=False)

Also, by devising the Model method and QuerySet, we can implement the view without writing many conditional branches.Here is an example.(I didn't actually move it, so it might not work well.Please keep it for reference only)

models.py

class Category (models.Model):
    parent=models.ForeignKey(Category, related_name='children', null=True, blank=True)
    name=models.CharField(max_length=255)
    slug=models.SlugField()

    @property
    default big_cat(self):
        # If parent is null, return yourself as it is a parent category
        if not self.parent:
            return self
        # Otherwise return parent category (parent)
        else:
            return self.parent

    def__str__(self):
        return self.name

class Location (models.Model):
    parent=models.ForeignKey (State, related_name='children', null=True, blank=True)
    name=models.CharField(max_length=255)
    slug=models.SlugField()

    @property
    def state(self):
        # If the parent is null, it is State, so return yourself.
        if not self.parent:
            return self
        # Otherwise return State(parent)
        else:
            return self.parent

    def__str__(self):
        return self.name

classPostQuerySet(models.QuerySet):

    def filter_category(self, category):
        if not category.parent:
            # If it's a Big Category, filter the Posts that belong to the children category.
            return self.filter(category__in=category.children.all())
        else:
            # For Small Category, filter the Posts belonging to the category.
            return self.filter(category=category)

    def filter_location(self, location):
        if not location.parent:
            # If it is State, filter the Post belonging to the location of children.
            return self.filter(location__in=location.children.all())
        else:
            # If it is a Region, filter the Post belonging to that location.
            return self.filter(location=location)


class Post (models.Model):
    category=models.ForeignKey(Category)
    location=models.ForeignKey (Location)
    title=models.CharField(max_length=255)
    text=models.CharField(max_length=255)

    objects=PostQuerySet.as_manager()

    def__str__(self):
        return self.title

views.py

 from django.shortcuts import get_object_or_404

from.models import Category, Location, Post


def cat_index(request, cat):
    category=get_object_or_404(Category,slug=cat)
    return render(request, 'classifieds/index.html', {
        'big_cat': category.big_cat,
        'states': Location.objects.filter(parent__isnull=True).all(),
        'posts': Post.objects.filter_category(category).all()
    })


def loc_index(request, cat, loc):
    category=get_object_or_404(Category,slug=cat)
    location=get_object_or_404(Location,slug=loc)
    ctx = {
        'big_cat': category.big_cat,
        'state': location.state,
        'posts': Post.objects.filter_category(category).filter_location(location).all()
    }
    if not category.parent:
        ctx.update({'selected_cat':'big'})
    else:
        ctx.update({'small_cat_for_loc':category})
    return render (request, 'classifieds/index.html', ctx)


2022-09-30 21:22

If you have any answers or tips


© 2024 OneMinuteCode. All rights reserved.