【问题标题】:use searializer field in template Django Rest Framework在模板 Django Rest Framework 中使用序列化器字段
【发布时间】:2018-05-13 10:28:25
【问题描述】:

我是 Django Rest Framework 的新手,正在编写第一个 API 应用程序。

我的contacts/models.py

class Contact(models.Model):
    user_id = models.ForeignKey(User, on_delete=models.CASCADE)
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100, blank=True, null=True)
    date_of_birth = models.DateField(blank=True, null=True)

    class Meta:
        db_table = 'contacts'

    def full_name(self):
        return self.first_name + ' ' + self.last_name

    def __str__(self):
        return self.full_name()


class ContactEmail(models.Model):
    contact = models.ForeignKey(Contact, on_delete=models.CASCADE)
    email = models.EmailField()
    primary = models.BooleanField(default=False)

    class Meta:
        db_table = 'contact_emails'

    def __str__(self):
        return self.email

contacts/searializers.py

class ContactSerializer(serializers.HyperlinkedModelSerializer):
    primary_email = serializers.SerializerMethodField()

    class Meta:
        model = Contact
        fields = ('url', 'full_name', 'date_of_birth', 'primary_email')

    def get_primary_email(self, obj):
        primary_email = obj.contactemail_set.filter(primary=True).first()

        if primary_email:
            return primary_email.email

        return ''

contacts/views.py

class ContactViewSet(viewsets.ModelViewSet):
    queryset = Contact.objects.all()
    serializer_class = ContactSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,
                          IsOwnerOrReadOnly,)

    def perform_create(self, serializer):
        serializer.save(user_id=self.request.user)

class ContactList(APIView):
    renderer_classes = [TemplateHTMLRenderer]
    template_name = 'contacts/list.html'
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

    def get(self, request):
        queryset = Contact.objects.all()
        return Response({'contacts': queryset})

http://<ip>:<port>/api/contacts 可以访问ContactViewSet,http://<ip>:<port>/contacts 可以访问ContactList

http://<ip>:<port>/api/contacts 在 json 响应中给出 primary_email 但在 list.html {{ contact.primary_email }}

中使用时没有打印任何内容

我不能在使用 **APIView 时使用序列化器字段吗?**

是否需要重写ContactList()中的函数来获取primary_email字段?

编辑 2:contacts/list.html

{% for contact in contacts %}
    <h4 class="card-title">{{ contact.full_name }}</h4>
    <h5>{{ contact.primary_email }}
    <a href="{% url 'contact:detail' contact.pk %}">Click here</a>
{% endfor %}

这是打印用户的全名,但不是主电子邮件

【问题讨论】:

  • 可以看到contacts/list.html吗?
  • 见Edit 2。已添加contacts/list.html

标签: django django-rest-framework


【解决方案1】:

您必须使用APIView 中的序列化程序才能访问其字段。您还需要使用 Django render 助手在上下文中传递联系人以呈现模板,因为 APIView 不知道如何呈现自定义模板。

一种选择是在将数据添加到您的联系人列表中的上下文之前对其进行序列化。像这样的:

from django.shortcuts import render


class ContactList(APIView):
    renderer_classes = [TemplateHTMLRenderer]
    template_name = 'contacts/list.html'
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

    def get(self, request):
        serialized_contacts = ContactSerializer(
            Contact.objects.all(), many=True).data
        context = {'contacts': serialized_contacts}
        return render(request, self.template_name, context)

但我没有看到在该视图中使用 APIView 或序列化程序的理由。我会做什么:

  1. 将primary_email 属性添加到Contact 模型:

    class Contact(models.Model):
        user_id = models.ForeignKey(User, on_delete=models.CASCADE)
        first_name = models.CharField(max_length=100)
        last_name = models.CharField(max_length=100, blank=True, null=True)
        date_of_birth = models.DateField(blank=True, null=True)
    
        class Meta:
            db_table = 'contacts'
    
        @property
        def full_name(self):
            return self.first_name + ' ' + self.last_name
    
        @property
        def primary_email(self):
            primary_email = self.contactemail_set.filter(primary=True).first()
    
            if primary_email:
                return primary_email.email
    
            return ''
    
        def __str__(self):
            return self.full_name
    
  2. 有了这个新模型,就不需要在ContactSerializer 中定义get_primary_email 方法:

    class ContactSerializer(serializers.HyperlinkedModelSerializer):
        primary_email = serializers.SerializerMethodField()
    
        class Meta:
            model = Contact
            fields = ('url', 'full_name', 'date_of_birth', 'primary_email')
    
  3. 我将使用 Django 的 generics.ListView,而不是使用 APIView 作为 ContactList 视图。

    from django.views.generic import ListView
    from django.contrib.auth.mixins import LoginRequiredMixin
    
    
    class ContactList(LoginRequiredMixin, ListView):
        template_name = 'contacts/list.html'
        permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
        queryset = Contact.objects.all()
    

【讨论】:

  • 是的,我在模型类中添加了函数,APIView 和 API 都很容易使用,但我仍然需要回答这个问题,因为可能有很多我可以使用的函数'不要直接写在模型中。到时候你的答案就会派上用场。
猜你喜欢
  • 2018-06-07
  • 2019-07-20
  • 1970-01-01
  • 2015-12-19
  • 1970-01-01
  • 2016-12-10
  • 2013-07-07
  • 2013-09-12
  • 2015-02-19
相关资源
最近更新 更多