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实现:
- 创建序列化器:
# serializers.py from rest_framework import serializers from .models import Event class EventSerializer(serializers.ModelSerializer): class Meta: model = Event fields = ['id', 'name', 'description', 'date']
- 编写视图:
# 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'
- 配置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
相关产品推荐
相关产品推荐

