You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native Expo扫码跳转详情页及Django后端适配技术求助

解决方案

一、先解决二维码的唯一标识问题(必须修改)

当前你用Event的name生成二维码,但name可能重复,会导致扫码后无法正确匹配唯一的Event。建议改用Event的id(数据库自动生成的唯一主键)来生成二维码:

修改Django的Event模型save方法:

def save(self, *args, **kwargs):
    if not self.qr_code:
        # 把self.name改成str(self.id),用唯一的id生成二维码
        qrcode_img = qrcode.make(str(self.id))
        canvas = Image.new('RGB', (qrcode_img.pixel_size, qrcode_img.pixel_size), 'white')
        canvas.paste(qrcode_img)
        fname = f'{self.name}.png'
        buffer = BytesIO()
        canvas.save(buffer, 'PNG')
        self.qr_code.save(fname, ContentFile(buffer.getvalue()), save=False)
    super().save(*args, **kwargs)

注意:修改后需要重新生成已存在Event的二维码,或者手动删除旧的qr_code字段值,让save方法重新生成。

二、添加Django后端API接口

你需要一个根据Event id获取详情的API接口,用Django REST Framework实现:

  1. 创建序列化器:
# serializers.py
from rest_framework import serializers
from .models import Event

class EventSerializer(serializers.ModelSerializer):
    class Meta:
        model = Event
        fields = ['id', 'name', 'description', 'date']
  1. 编写视图:
# views.py
from rest_framework import generics
from .models import Event
from .serializers import EventSerializer

class EventDetailView(generics.RetrieveAPIView):
    queryset = Event.objects.all()
    serializer_class = EventSerializer
    lookup_field = 'pk'
  1. 配置URL:
# urls.py
from django.urls import path
from .views import EventDetailView

urlpatterns = [
    path('api/events/<int:pk>/', EventDetailView.as_view(), name='event-detail'),
]

三、修改React Native扫码页面(无需大改)

扫码后拿到的data现在是Event的id,直接传去详情页即可,你的现有代码逻辑没问题:

const handleBarCodeScanned = ({ type, data }) => {
    setScanned(true);
    if (data) {
        navigation.navigate('Event', {eventId: data} )
    }
};

四、修改EventDetailScreen,从后端获取完整数据

当前你的详情页试图直接从route.params拿name和description,但实际上扫码后只传了eventId,需要发起网络请求获取完整数据:

import { useNavigation, useRoute } from "@react-navigation/native";
import { useLayoutEffect, useState, useEffect } from "react";
import { View, Text, StyleSheet, ActivityIndicator } from "react-native";
import { HeaderBackButton } from '@react-navigation/elements';

const EventDetailScreen = () => {
    const route = useRoute()
    const navigation = useNavigation()
    const [event, setEvent] = useState(null);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(null);
    const { eventId } = route.params;

    // 加载Event详情
    useEffect(() => {
        const fetchEvent = async () => {
            try {
                // 替换成你的Django后端实际IP和端口
                const response = await fetch(`http://你的后端IP:8000/api/events/${eventId}/`);
                if (!response.ok) {
                    throw new Error('获取事件失败');
                }
                const data = await response.json();
                setEvent(data);
                navigation.setOptions({ headerTitle: data.name });
            } catch (err) {
                setError(err.message);
            } finally {
                setLoading(false);
            }
        };

        fetchEvent();
    }, [eventId, navigation]);

    useLayoutEffect(()=>{
        navigation.setOptions({
            headerLeft: () => (
                <HeaderBackButton
                    tintColor="white"
                    onPress={()=> navigation.goBack()}
                />
            )
        })
    }, [navigation])

    // 加载状态
    if (loading) {
        return (
            <View style={Styles.screen}>
                <ActivityIndicator size="large" />
            </View>
        );
    }

    // 错误状态
    if (error) {
        return (
            <View style={Styles.screen}>
                <Text style={{fontSize: 18}}>错误:{error}</Text>
            </View>
        );
    }

    // 正常渲染
    return (
        <View style={ Styles.screen }>
            <Text style={{fontSize: 24, fontWeight: 'bold', marginBottom: 10}}>{event.name}</Text>
            <Text style={{fontSize: 16, marginBottom: 20}}>日期:{event.date}</Text>
            <Text style={{fontSize: 18}}>{event.description}</Text>
        </View>
    );
}

const Styles = StyleSheet.create({
    screen: {
        padding:20,
        flex:1,
        justifyContent:'center',
        alignItems:'center'
    }
})

export default EventDetailScreen

额外注意事项

  • 确保Django后端开启CORS,允许React Native应用访问,可安装django-cors-headers包并配置
  • 测试时不要用localhost,要用电脑/服务器的实际IP地址,否则模拟器/真机无法访问后端
  • 之前生成的旧二维码(用name生成的)需要重新生成,否则扫码无法匹配到正确的Event

内容的提问来源于stack exchange,提问作者Justin Boucher

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 03:34:51