использовать поле поисковика в шаблоне Django Rest Framework - PullRequest
0 голосов
/ 13 мая 2018

Я новичок в Django Rest Framework и пишу первое приложение API.

my 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

контакты / 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 ''

контакты / 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})

Где ContactViewSet доступно для http://<ip>:<port>/api/contacts и ContactList доступно для http://<ip>:<port>/contacts

http://<ip>:<port>/api/contacts дает primary_email в ответе json, но ничего не печатает при использовании в 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 %}

Это печатает полное имя пользователя, но не основной адрес электронной почты

1 Ответ

0 голосов
/ 14 мая 2018

Вы должны использовать сериализатор в 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. С этой новой моделью,не было бы необходимости иметь метод get_primary_email, определенный в ContactSerializer:

    class ContactSerializer(serializers.HyperlinkedModelSerializer):
        primary_email = serializers.SerializerMethodField()
    
        class Meta:
            model = Contact
            fields = ('url', 'full_name', 'date_of_birth', 'primary_email')
    
  3. Вместо использования APIView для представления ContactList, я быиспользуйте generics.ListView от Django.

    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()
    
...