Ahmad Saeed
Ahmad Saeed

Reputation: 11

filter queryset based on django countries field

this is my viewset:

class PollViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = Poll.objects.all()
    serializer_class = PollSerializer()

    def get_queryset(self):
        country = self.kwargs.get('pk', None)
        if country is not None:
            django_countries.Countries.name(country)
            return self.queryset.filter(personality__country__name=country)
        else:
            country = self.request.user.preferred_country
            return self.queryset.filter(personality__country=country)

model.py :

from django_countries.fields import CountryField



    class Personality(models.Model):
        name = models.CharField(max_length=100)
        bio = models.TextField()
        age = models.IntegerField()
    
        class Gender(models.TextChoices):
            MALE = 'MALE', _('Male')
            FEMALE = 'FEMALE', _('Female')
            OTHER = 'OTHER', _('Other')
    
        gender = models.CharField(
            max_length=6,
            choices=Gender.choices,
            default=Gender.MALE,
        )
    
        country = CountryField(null=True)
        picture = models.ImageField(upload_to='uploads/profile_images/%Y/%m/%d')
    
        created_at = models.DateTimeField(auto_now_add=True)
        updated_at = models.DateTimeField(auto_now=True)
    
        def __str__(self):
            return self.name



    class Poll(RulesModel):
        personality = models.OneToOneField(Personality, related_name='polls', on_delete=models.CASCADE)
        start_date = models.DateTimeField(null=True)
        end_date = models.DateTimeField(null=True)
    
        created_at = models.DateTimeField(auto_now_add=True)
        updated_at = models.DateTimeField(auto_now=True)
    
        def __str__(self):
            return 'poll#' + str(self.id) + ' ' + self.personality.name

Urls.py

from django.conf.urls.static import static
from django.urls import path, include

from liderate import settings
from .views import PollViewSet, PersonalityViewSet, PollListViewSet

from rest_framework import routers

router = routers.DefaultRouter()
router.register(r'polls', PollViewSet)
router.register(r'polls-list', PollListViewSet)
router.register(r'personalities', PersonalityViewSet)

urlpatterns = [
    path('', include(router.urls)),
]

here it raises exception that "Unsupported lookup 'name' for CountryField or join on the field not permitted."

this is raised in the if condition (else condition works perfectly fine). is there any other way of filtering the query set based on the country's name

i actually want to view only the polls related to country passed as a param in the get url

Upvotes: 1

Views: 1328

Answers (1)

Hassan Raza
Hassan Raza

Reputation: 27

I had a field named location_countries in my project model based on CountryField. It was a multiselect and I needed to create a search based on country name or any other information available in project's other fields. conventional ways e.g "filter(fieldname__icontains) or Q(fieldname__country__name) etc failed. After a lot of trouble, search and thinking, I finally devised a workaround that is working as I intended. Now by giving any keywords for example "samo" in my search field it returns all projects based in "American Samoa" or "afghan" and it retruns all projects based in "Afghanistan". Hope This helps you also. Search field in normal html input tag named "searchTxt". to avoid duplication i first converted result to set and then back to list.

    def viewProjects(request):
        if request.user.is_authenticated:
            if 'searchTxt'  in  request.GET:
                qry = request.GET['searchTxt']
        
            countries_list = []
            pros = Project.objects.all()
                for pro in pros:
            
                    for i in pro.location_countries:
                        if qry.lower() in i.name.lower():                       
                            countries_list.append(pro.project_heading)

        
            res=Project.objects.filter(project_heading__in=countries_list)
        
            projs = Project.objects.filter(                                                 
                                            Q(project_id__icontains=qry)|                                           
                                            Q(project_heading__icontains=qry) |
                                            Q(project_description__icontains=qry)|
                                            Q(sla_type__icontains=qry)|
                                            Q(project_type__icontains=qry)|
                                            Q(project_priority__icontains=qry)|
                                            Q(location_countries__exact=qry)|                                       
                                            Q(location_cities__icontains=qry)|                                      
                                            Q(project_manager__username__icontains=qry)|                                        
                                            Q(escalation_manager__username__icontains=qry)                                      
                                        )

        
        
            project = list(chain(res, projs))
            prj = set(project)
            projects=list(prj)
           
            context = { 'projects':projects }
            return render(request, 'admin_view_projects.html', context)
        else:   
            projects = Project.objects.all()
        
            context = { 'projects':projects }
            return render(request, 'admin_view_projects.html', context)
    else:
        return redirect('index')

Upvotes: 0

Related Questions