WutWut
WutWut

Reputation: 1234

Consuming api from django rest framework

I have used django rest api to create an api that looks like this -

{
"count": 2,
"next": null,
"previous": null,
"results": [
    {
        "url": "http://127.0.0.1:8000/app/student/1/",
        "id": 1,
        "title": "mr",
        "name": "student1",
        "address": "somewhere",
        "city": "Mumbai",
        "tests": [
            {
                "test_name": "Math",
                "section_1": "34",
                "section_2": "54",
                "date_added": "2015-12-15"
            }
        ]
    },
    {
        "url": "http://127.0.0.1:8000/app/student/2/",
        "id": 2,
        "title": "mr",
        "name": "student2",
        "address": "somewhere",
        "city": "Delhi",
        "tests": [
            {
                "test_name": "English",
                "section_1": "34",
                "section_2": "65",
                "date_added": "2015-12-15"
            }
        ]
    }
   ]
 }

I have another app in the same project the uses this data using something like this -

def Peoplelist(request):
    data= requests.get('http://127.0.0.1:8000/app/students/').json()
    send_list = []
    for i in range(2):
        send_list.append(data['results'][i]['name'])
    context = RequestContext(request, {
    'send_list': send_list,
})
return render_to_response('taskmanager/numbers.html', context)

which creates a list of the student names.

I want to display a list of student names depending on the city name and then click on the names to view the student and test details. Can't figure out how to do that. Can someone suggest a way?Thanks.

models.py
class Test(models.Model):
    date_added = models.DateField(default=datetime.datetime.now)
    test_name = models.CharField(max_length=200,default='',blank=False)
    section_1 = models.CharField(max_length=100,default='') 
    section_2 = models.CharField(max_length=100,default='') 

    def __str__(self):
        return self.test_name

class Person(models.Model):
    tests = models.ManyToManyField(Test)
    title = models.CharField(max_length=3,default="mr",blank=False)
    name = models.CharField(max_length=50,default='',blank=False)
    address = models.CharField(max_length=200,default='',blank=False)
    city = models.CharField(max_length=100,default='',blank=False)

    def __str__(self):
        return self.name

serializers.py
class TestSerializer(serializers.ModelSerializer):
    class Meta:
        model = Test
        fields = ('test_name','section_1','section_2','date_added')

class PersonSerializer(serializers.HyperlinkedModelSerializer):
    tests = TestSerializer(many=True, read_only=True)
    class Meta:
        model = Person
        fields = ('id','title', 'name', 'address', 'city','tests')

numbers.html

{% extends "index.html" %}
{% block names %}
{% for list in send_list %}
    <a href="/"><p>{{list}}</p></a>
{% endfor %}
{% endblock %}

******************************EDIT*************************

models.py

class City(models.Model):
   city_name=models.CharField(max_length=100,default='',blank=False)

   def __str__(self):
      return self.city_name
class Person(models.Model):
   tests = models.ManyToManyField(Test)
   title = models.CharField(max_length=3,default="mr",blank=False)
   name = models.CharField(max_length=50,default='',blank=False)
   address = models.CharField(max_length=200,default='',blank=False)
   city = models.CharField(max_length=100,default='',blank=False)

views.py

class StudentList(generics.ListCreateAPIView):
    queryset = Person.objects.all()
    serializer_class = PersonSerializer


class CityList(generics.ListCreateAPIView):
    queryset = City.objects.all()
    serializer_class = CitySerializer

class CityDetail(generics.ListCreateAPIView):
    city = City.objects.all()
    serializer_class = CitySerializer

class StudentDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer

Upvotes: 1

Views: 1822

Answers (2)

Rohit Jain
Rohit Jain

Reputation: 213193

So basically you need 3 different APIs:

  • /cities/ - Gives you list of cities.
  • /cities/<pk>/students - Gives you list of students in given city.
  • /students/<pk>/ - Gives details of Student with id pk.

So, that single API is not going to handle all 3 pages you want.

You'll need 3 template views:

def cities(request):
    data = requests.get('http://127.0.0.1:8000/app/cities/').json()
    context = RequestContext(request, {
        'cities': data.cities,
    })
    return render_to_response('taskmanager/cities.html', context)

def Peoplelist(request, pk):
    data = requests.get('http://127.0.0.1:8000/app/cities/' + pk + '/students/').json()
    context = RequestContext(request, {
        'students': data.students,
    })
    # Better rename this one to students.html
    return render_to_response('taskmanager/numbers.html', context)

def student_details(request, pk):
    data = requests.get('http://127.0.0.1:8000/app/students/' + pk).json()
    context = RequestContext(request, {
        'student': data.student,
    })
    return render_to_response('taskmanager/student_detail.html', context)

Configure the urls for these views. Now the templates would be like:

cities.html:

{% extends "index.html" %}
{% block names %}
{% for city in cities %}
    <a href="{% url 'student_list' city.id %}"><p>{{city.name}}</p></a>
{% endfor %}
{% endblock %}

students.html:

{% extends "index.html" %}
{% block names %}
{% for student in students %}
    <a href="{% url 'student_detail' student.id %}"><p>{{student.name}}</p></a>
{% endfor %}
{% endblock %}

student_detail.html:

{% extends "index.html" %}
{% block names %}
{{ student.name }}
<table>
    <tr>
    <th>Test Name</th>
    <th>Section 1</th>
    <th>Section 2</th>
    <th>Date Added</th>
    </tr>
{% for test in student.tests %}
    <tr>
        <td>{{ test.test_name }}</td>
        <td>{{ test.section_1 }}</td>
        <td>{{ test.section_2 }}</td>
        <td>{{ test.date_added }}</td>
    </tr>
{% endfor %}
</table>
{% endblock %}

Modification in models:

Since you've now a City model, you can change the city field to ForeignKey in Person model. Also, let's rename Person to Student:

class Student(models.Model):
   # Removing the tests field. Rather add `student` field in `Test` model
   # tests = models.ManyToManyField(Test)
   title = models.CharField(max_length=3,default="mr",blank=False)
   name = models.CharField(max_length=50,default='',blank=False)
   address = models.CharField(max_length=200,default='',blank=False)
   city = models.ForeignKey(City)

then change the Test model:

class Test(models.Model):
    student = models.ForeignKey(Student)
    date_added = models.DateField(default=datetime.datetime.now)
    test_name = models.CharField(max_length=200,default='',blank=False)
    section_1 = models.CharField(max_length=100,default='') 
    section_2 = models.CharField(max_length=100,default='') 

    def __str__(self):
        return self.test_name

For views:

  • /cities/ - For this CityList view in your code is fine.
  • /cities/<pk>/students/ - For this, change your StudentList view like this:

    class StudentList(generics.ListCreateAPIView):
        serializer_class = PersonSerializer
    
        def get_queryset(self):
            city = City.objects.get(pk=self.kwargs.get('pk', None))
            students = Student.objects.filter(city=city)
            return students
    

And then for last one:

  • /students/<pk>/ - StudentDetail view would be like:

    class StudentDetail(generics.RetrieveAPIView):
        serializer_class = PersonSerializer
    
        def get_object(self):
            student_id = self.kwargs.get('pk', None)
            return Student.objects.get(pk=student_id)
    

Now for serializers, change your PersonSerializer to this one:

class StudentSerializer(serializers.ModelSerializer):
    test_set = TestSerializer(many=True, required=False)

    class Meta:
        model = Student
        fields = ('id','title', 'name', 'address', 'city', 'test_set')

Upvotes: 3

Dhia
Dhia

Reputation: 10609

If I correctly understand, you want to have hyperlink for students in your api response. Inorder to this add the following in serializer.py:

class StudentByCityField(serializers.RelatedField):
    def to_representation(self, city):
        student_list = self.objects.filter(city=city)
        link_list = list()
        append_link = link_list.append
        for student in student_list:
            append_link("/app/students/%s" % student.name)
        return link_list

class PersonByCitySerializer(serializers.ModelSerializer):
    city_name = StudentByCityField(source='city', read_only=True)
    class Meta:
        model = Test
        fields = ('city_name',)

But in case you want to do this HTML side this will be trivial

  1. views.py
def get_cities(request):
    pesrons = Person.objects.all()
    pesrons.query.group_by = ['city']
    city_set = set([i.city for i in persons])
    context = RequestContext(request, {
        'city_list': list(city_set),
    })
    return render_to_response('cities.html', context)

def get_students_by_city(request, city):
    student_list = Person.objects.filter(city=city)
    context = RequestContext(request, {
        'students': student_list,
    })
    # Better rename this one to students.html
    return render_to_response('students_by_city.html', context)

def get_student_details(request, id):
    student = Person.objects.get(id=id)
    context = RequestContext(request, {
        'student': student,
    })
    return render_to_response('student_detail.html', context)
  1. templates

cities.html

    {% extends "index.html" %}
    {% block names %}
    <ul>
    {% for city in city_list %}
        <li><a href="{% url 'student_by_city' city.name %}">
        {{city.name}}
        </a></li>
    {% endfor %}
    </ul>
    {% endblock %}

students_by_city.html

{% extends "index.html" %}
{% block names %}
<ul>
{% for student in student_list %}
    <li><a href="{% url 'student_detail' student.id %}"><p>{{student.name}}</p></a></li>
{% endfor %}
</ul>
{% endblock %}

student_detail.html

{% extends "index.html" %}
{% block names %}

   <!-- Display here your data as you like -->

{% endblock %}
  1. urls.py
urlpatterns = patterns('',

    url(r'^app/cities/$', views.get_cities, name="participant-register"), 
    url(r'^app/students/(?P<id>\d+)$', views.get_student_by_city, name="student_by_city"),
    url(r'^app/student/(?P<city>\w+/$', views.get_student_detail, name="student_detail"),                       
)

Upvotes: 1

Related Questions