提问人:ej719 提问时间:11/17/2023 最后编辑:ej719 更新时间:11/17/2023 访问量:26
用户特定数据渲染全栈
User Specific Data Rendering Full Stack
问:
我正在使用 React 和 Django 创建一个完整的堆栈 Web 应用程序,它允许用户上传一个 XML 文件,然后将其转换为多个 JSON 对象并呈现为多个 JSON 对象。由于文件非常大,我实现了分页。
目前,我遇到了一个尝试使数据特定于用户的问题。我可以上传文件,但相同的数据呈现在多个用户的配置文件上。
这是我的相关代码:
API 调用
const getFile = (uid) =>
new Promise((resolve, reject) => {
fetch(`${clientCredentials.databaseURL}/files`)
.then((response) => response.json())
.then(resolve)
.then(reject);
});
const createFile = (formData) =>
new Promise((resolve, reject) => {
fetch(`${clientCredentials.databaseURL}/files/`, {
method: 'POST',
// headers: {
// 'Content-Type': 'multipart/form-data',
// Accept: 'application/json',
// // type: 'formData',
// },
body: formData,
})
.then((response) => resolve(response.json()))
.catch((error) => reject(error));
});
文件格式
const initialState = {
xml: null,
log: {
dateStart: '',
dateEnd: '',
dateGenerated: '',
user: 1,
},
entry: {
type: '',
date: '',
details: '',
zczc: '',
},
};
function FileForm({ fileObj }) {
const [fileList, setFileList] = useState(initialState);
const router = useRouter();
const { user } = useAuth();
console.warn(user);
useEffect(() => {
if (fileObj.xml) {
setFileList((prevState) => ({
...prevState,
xml: fileObj.xml,
}));
}
}, [fileObj]);
// XML READER FUNCTIONALITY
function xmlToJson(xmlDoc) {
const result = {};
if (xmlDoc.hasChildNodes()) {
for (let i = 0; i < xmlDoc.childNodes.length; i++) {
const item = xmlDoc.childNodes[i];
if (item.nodeType === 1) {
// Element node
result[item.nodeName] = xmlToJson(item);
} else if (item.nodeType === 3) {
// Text node
result.value = item.textContent;
}
}
}
return result;
}
const handleFileChange = (e) => {
const file = e.target.files[0];
const reader = new FileReader();
reader.onload = () => {
const xmlString = reader.result;
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(xmlString, 'text/xml');
const jsonData = xmlToJson(xmlDoc);
setFileList({
xml: xmlString,
log: {
dateStart: jsonData.log.dateStart.value,
dateEnd: jsonData.log.dateEnd.value,
dateGenerated: jsonData.log.dateGenerated.value,
},
entry: {
type: jsonData.log.entry.type.value,
date: jsonData.log.entry.date.value,
details: jsonData.log.entry.details.value,
zczc: jsonData.log.entry.zczc.value,
},
});
};
reader.readAsText(file);
};
// new
const handleUploadClick = (e) => {
e.preventDefault();
const { xml, log, entry } = fileList;
if (!xml || !log || !entry) {
return; // Exit if any of the required fields is missing
}
const parsedDate = new Date(entry.date); // Assuming entry.date is the date value from XML
const isoFormattedDate = parsedDate.toISOString();
const formData = new FormData();
formData.append('xml', new File([xml], 'filename.xml')); // Append the file directly
// formData.append('xml', xml, 'filename.xml'); // Append the file directly
formData.append('log', JSON.stringify(log));
console.warn(log); // Convert log object to JSON string and append
// formData.append('entry', JSON.stringify(entry)); // Convert entry object to JSON string and append
formData.append('entry', JSON.stringify({ ...entry, date: isoFormattedDate }));
formData.append('uid', user && user.uid);
console.warn(user.uid);
console.warn('this is form data', ...formData);
createFile(formData)
.then(() => router.push('/log'))
.catch((error) => console.error(error));
};
return (
<div>
<input type="file" onChange={handleFileChange} />
{fileList && (
<ul>
<li>
{fileList.name} - {fileList.type}
</li>
</ul>
)}
<Button type="submit" onClick={handleUploadClick}>
Upload
</Button>
{fileList && <FileCard user={user} fileObj={fileList} onUpdate={viewFileDetails} />}
</div>
);
}
FileForm.propTypes = {
user: PropTypes.shape({
uid: PropTypes.string,
}).isRequired,
fileObj: PropTypes.shape({
id: PropTypes.number,
xml: PropTypes.string,
log: PropTypes.shape({
dateStart: PropTypes.string,
dateEnd: PropTypes.string,
dateGenerated: PropTypes.string,
}),
entry: PropTypes.shape({
type: PropTypes.string,
date: PropTypes.string,
details: PropTypes.string,
zczc: PropTypes.string,
}),
// user: PropTypes.shape({
// id: PropTypes.number,
// name: PropTypes.string,
// email: PropTypes.string,
// uid: PropTypes.string,
// }),
}),
};
console.warn('These are proptypes', FileForm.propTypes);
FileForm.defaultProps = {
fileObj: initialState,
};
export default FileForm;
日志 .js
const LogPage = () => {
const [files, setFiles] = useState([]);
const [page, setPage] = useState(1);
const [hasNext, setHasNext] = useState(false);
// const [filteredFiles, setFilteredFiles] = useState([]);
const { user } = useAuth();
// new
const getAllFiles = (pageNumber) => {
fetch(`${clientCredentials.databaseURL}/files/?page=${pageNumber}&page_size=50`)
.then((response) => response.json())
.then((data) => {
setFiles(data.results);
setHasNext(data.next !== null);
})
.catch((error) => console.error(error));
};
useEffect(() => {
getAllFiles(page); // Load the initial page (page 1)
return () => {
};
}, [page]);
const handleNextPage = () => {
if (hasNext) {
getAllFiles(page + 1, user.uid);
setPage((prevPage) => prevPage + 1);
}
};
const handlePrevPage = () => {
if (page > 1) {
getAllFiles(page - 1, user.uid); // Load the previous page
setPage((prevPage) => prevPage - 1); // Update the page state
}
};
return (
<div>
<div className="d-flex flex-wrap">
<title>EAS Document Browser</title>
<br />
<br />
<h1 style={{ color: 'white' }}>Your Logs</h1>
</div>
<br />
<Link href="/log/new" passHref>
<Button className="btn btn-danger">Upload a Document</Button>
</Link>
<br />
<br />
<div className="d-flex flex-wrap flex-row">
{files && files.map((file) => <FileCard user={user} key={file.id} fileObj={file} onUpdate={getAllFiles} />)}
</div>
<div>
<br />
<br />
{page > 1 && <Button onClick={handlePrevPage}>Previous Page</Button>}
{hasNext && (
<Button onClick={handleNextPage} className="justify-content-right">
Next Page
</Button>
)}
</div>
</div>
);
};
export default LogPage;
Django 模型:
class Log(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
dateStart = models.DateTimeField(max_length=20)
dateEnd = models.DateTimeField(max_length=20)
dateGenerated = models.DateTimeField(max_length=20)
log_hash = models.CharField(max_length=255)
def __str__(self):
return self.name
class Entry(models.Model):
type = models.CharField(max_length=50)
date = models.DateTimeField(default=timezone.now)
details = models.CharField(max_length=500)
zczc = models.CharField(max_length=200)
log = models.ForeignKey(Log, on_delete=models.CASCADE)
def __str__(self):
return self.name
class Files(models.Model):
xml = models.FileField(upload_to='uploads')
log = models.ForeignKey(Log, on_delete=models.CASCADE)
entry = models.ForeignKey(Entry, on_delete=models.CASCADE)
def __str__(self):
return self.xml
文件视图集:
class CustomPageNumberPagination(PageNumberPagination):
page_size = 50 # Number of entries per page
page_size_query_param = 'page_size'
max_page_size = 100
# class XMLView(ViewSet):
class XMLViewSet(viewsets.ViewSet):
parser_classes = [MultiPartParser, FormParser]
def create(self, request):
user_uid = request.data['uid']
print(user_uid)
# Validate the user UID
try:
user = User.objects.get(uid=user_uid)
print(user)
except User.DoesNotExist:
return Response({'error': f"User with UID {user_uid} not found."}, status=status.HTTP_400_BAD_REQUEST)
# Access the uploaded XML file from the request object
file = request.FILES.get('xml')
print(file)
if not file:
return Response({'error': 'No XML file uploaded.'}, status=status.HTTP_400_BAD_REQUEST)
# Read the contents of the file
file_content = file.read().decode('utf-8')
# Parse the XML content
try:
tree = ElementTree.fromstring(file_content)
except ElementTree.ParseError:
return Response({'error': 'Invalid XML format.'}, status=status.HTTP_400_BAD_REQUEST)
# Access XML data
for entry_data in tree.findall('entry'):
log_date_start = tree.findtext('dateStart')
log_date_end = tree.findtext('dateEnd')
date_generated = tree.findtext('dateGenerated')
# Generate a unique identifier based on log attributes
log_identifier = f"{log_date_start}-{log_date_end}-{date_generated}"
# Create or get the Log instance using the unique identifier
log_instance, created = Log.objects.get_or_create(
user=user,
log_hash=log_identifier,
defaults={
'dateStart': log_date_start,
'dateEnd': log_date_end,
'dateGenerated': date_generated
}
)
if not created:
# If the Log instance already exists, update the fields if necessary
log_instance.dateStart = log_date_start
log_instance.dateEnd = log_date_end
log_instance.dateGenerated = date_generated
log_instance.save()
entry_type = entry_data.findtext('type')
entry_date = entry_data.findtext('date')
entry_details = entry_data.findtext('details')
entry_zczc = entry_data.findtext('zczc')
entry_date = datetime.strptime(entry_date, '%m/%d/%y %H:%M:%S').strftime('%Y-%m-%d %H:%M:%S')
if not entry_zczc:
entry_zczc = None
try:
# Create or update the Entry instance
entry_instance, _ = Entry.objects.update_or_create(
log=log_instance,
type=entry_type,
date=entry_date,
details=entry_details,
zczc=entry_zczc
)
except Exception as e:
print(f"Error creating Entry instance: {e}")
return Response({'message': 'XML file successfully processed.'}, status=status.HTTP_200_OK)
def retrieve(self, request, pk):
try:
file = Files.objects.get(pk=pk)
except Files.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
serializer = FilesSerializer(file)
return Response(serializer.data)
## pagination refactored by ID
def list(self, request):
paginator = CustomPageNumberPagination()
# Order the queryset by a specific field (for example, 'id')
files = Files.objects.order_by('id')
result_page = paginator.paginate_queryset(files, request)
serializer = FilesSerializer(result_page, many=True)
return paginator.get_paginated_response(serializer.data)
def destroy(self, request, pk):
logXML = Files.objects.get(pk=pk)
logXML.delete()
return Response(None, status=status.HTTP_204_NO_CONTENT)
class FilesSerializer(serializers.ModelSerializer):
log = LogSerializer()
entry = EntrySerializer()
class Meta:
model = Files
fields = ['id', 'log', 'entry']
我尝试在前端和后端进行调整 - 调整以用户和文件形式传递的 proptype、API 调用中的参数以及服务器端的用户身份验证逻辑。这似乎是前端的一个简单的答案,所以我希望我的代码的另一双眼睛将有助于找到我忽略的明显问题。
答: 暂无答案
评论