Django REST API en Client

 Hier is een aangepaste Django REST Framework-client die offers kopieert via een API in plaats van direct in de database. Het gebruikt requests om de API-oproepen uit te voeren en stuurt de offers in JSON-formaat naar een andere server:

import requests
from django.conf import settings
from offers.models import Offer  # Zorg dat je Offer-model correct is ingesteld in je Django-app.

class OfferSyncClient:
    def __init__(self, api_base_url, api_token):
        """
        Initialiseer de client met de API basis-URL en authenticatietoken.
        """
        self.api_base_url = api_base_url
        self.headers = {
            "Authorization": f"Token {api_token}",
            "Content-Type": "application/json",
        }

    def sync_offers(self, contact_types, post_codes):
        """
        Kopieer de offers gebaseerd op contact types en postcodes via API.
        """
        for ct in contact_types:
            self._sync_offers_by_type(ct, post_codes)

    def _sync_offers_by_type(self, contact_type, post_codes):
        """
        Kopieer offers voor een specifieke contact type.
        """
        offers = Offer.objects.filter(contact_type=contact_type, post_code__in=post_codes, section="sale")
        print(f"Syncing {offers.count()} offers for contact type: {contact_type}")
        for offer in offers:
            self._send_offer_to_api(offer)

    def _send_offer_to_api(self, offer):
        """
        Stuur een enkele offer naar de API.
        """
        payload = {
            "slug": offer.slug,
            "property_id": offer.property_id,
            "title": offer.title,
            "realty_type": offer.realty_type,
            "section": offer.section,
            "post_code": offer.post_code,
            "location": offer.location,
            "address": offer.address,
            "price": str(offer.price) if offer.price else None,
            "total_surface": offer.total_surface,
            "livable_surface": offer.livable_surface,
            "short_description": offer.short_description,
            "number_of_bedrooms": offer.number_of_bedrooms,
            "bathrooms": offer.bathrooms,
            "furnished": offer.furnished,
            "type_of_construction": offer.type_of_construction,
            "monthly_costs": offer.monthly_costs,
            "for_index": offer.for_index,
            "hash": offer.hash,
            "property_url": offer.property_url,
            "created": offer.created.isoformat() if offer.created else None,
            "last_status_update": offer.last_status_update.isoformat() if offer.last_status_update else None,
            "contact_type": offer.contact_type,
            "status": offer.status,
            "phone": offer.contact.phone if offer.contact else None,
            "mobile": offer.contact.mobile if offer.contact else None,
            "contacted": offer.contacted,
            "contacted_date": offer.contacted_date.isoformat() if offer.contacted_date else None,
            "nota": offer.nota,
            "image_url": offer.main_image,
            "deal_stage": offer.deal_stage,
            "user": offer.user.id if offer.user else None,
        }

        try:
            response = requests.post(f"{self.api_base_url}/offers/", json=payload, headers=self.headers)
            response.raise_for_status()
            print(f"Offer {offer.id} successfully synced.")
        except requests.exceptions.RequestException as e:
            print(f"Failed to sync offer {offer.id}: {e}")

# Gebruik de client in een Django management command of service
from django.core.management.base import BaseCommand
from leads.models import LeadsConfig

class Command(BaseCommand):
    help = "Sync offers with external API"

    def handle(self, *args, **options):
        config = LeadsConfig.objects.first()
        if not config:
            self.stdout.write("No configuration found.")
            return

        post_codes = [int(code.strip()) for code in config.postcodes.split(',')]
        contact_types = [ct.strip() for ct in config.contact_type.split(',')]
        
        client = OfferSyncClient(api_base_url=settings.EXTERNAL_API_BASE_URL, api_token=settings.EXTERNAL_API_TOKEN)
        client.sync_offers(contact_types, post_codes)
 

To manage API tokens for Django Rest Framework (DRF) users through the Django admin interface, follow these steps:

Step 1: Enable the authtoken app

Ensure that rest_framework.authtoken is included in your INSTALLED_APPS:

INSTALLED_APPS = [
    ...
    'rest_framework',
    'rest_framework.authtoken',
]
 

python manage.py migrate
 

 Token model in the Django Admin is already registered and you will see model in admin to create a Token by user.


# This is only for API  
class OfferViewSet(viewsets.ModelViewSet):
    queryset = Offer.objects.all()
    serializer_class = OfferSerializer
    #permission_classes = [permissions.IsAuthenticated]

def is_staff_and_can_update_offer(user):
    """
    Custom test function to check if a user is both a staff member and has
    the 'change_bauwensoffer' permission in the bauwens.models application.
    """
    # Check if the user is a staff member
    if user.is_staff:
        return True
    # Check if the user has the permission to change BauwensOffer objects
    if user.has_perm('leads.change_offer'):
        return True
    # has the permission in group
    if 'leads.change_offer' in user.get_group_permissions():
        return True
    return False


In setting 

REST_FRAMEWORK = {
    # Use Django's standard `django.contrib.auth` permissions
    # Authenticated users require specific model-level permissions
    # Unauthenticated users are denied access
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ],
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.TokenAuthentication',
    ],
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 100,
}

In urls you need something like this. 

urlpatterns = [
    path('admin/login/', CustomAdminLoginView.as_view(), name='admin-login'),
    path('', IndexView.as_view(), name='index'),
    path('admin/', admin.site.urls),
    path('lead/', include('lead.urls')),
    path('api-auth/', include('rest_framework.urls')),
    path('api/', include(router.urls)),
] +  static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)





Comments