Jak wywołać przekierowanie URL na inny adres po imporcie wielu plików?

0

Witajcie,

Piszę apkę na Django do konwertowania plików PDF. Nie mogę sobie poradzić z jednym zagadnieniem, może ktoś byłby w stanie rzucić okiem i sprawdzić co robię źle? Mogę zaimportować ile chce plików PDF, wszystkie trafiają do bazy Postgresql, każdy plik ma przypisany numer uuid, form tag przez który importuje mam zabezpieczony tokenem CSRF w głównym template 'index.html' i z niego uruchamiam plik Javascriptu.

<form class="file-selector">
  {% csrf_token %}
  <div id="uploadContainer">
    <label for="fileInput" id="selectButton">Click here to convert PDF</label>
    <input type="file" id="fileInput" style="display: none;" multiple>
  </div>
  <div id="uploadStatusContainer"></div>
  <script defer src="{% static 'converter/javascript/import.js' %}"></script>
</form>

Jeśli proces importu się uda to pojawia się lista plików w tym samym oknie, każda pozycja zawiera nazwę pliku i przycisk.
Zamysł jest taki, żeby po kliknięciu w przycisk apka przekierowała na kolejny zdefiniowany template 'document_preview.html', który pokaże co ten plik zawiera.
Jeśli wewnątrz kodu Javascript za tym ifem wsadzę na sztywno deklaracje zmiennej 'uuid' i 'window.location.href' to przekierowanie działa, ale użytkownik traci możliwość wybrania, który plik chce podejrzeć po prostu otwiera pierwszy zaimportowany z kolejki.

if (data.success) {
    updateImportedFilesList(data.documents);
    const uuid = data.id_uuid;
    console.log('Redirecting to:', `${window.location.origin}/document/${uuid}/`);
    window.location.href = `${window.location.origin}/document/${uuid}/`;
}

Efekt wygląda tak, informacje o pliku się pokazują, adres URL jest prawidłowy czyli local/document/uuid

image
Ale jak próbuje wywołać to z poziomu funkcji updateImportedFilesList(documents) gdy otrzymam już listę plików po imporcie, wybiorę plik i kliknę w przycisk uruchamiając funkcje singleConvert(id_uuid) to się wysypuje ... Nie czaje o co chodzi bo uuid jak i token są prawidłowe do samego końca, dziwne jest to że adres URL zmienia się na local/token_csrf zamiast na local/document/uuid

image

image

Zastanawia mnie error 'Broken pipe from ('127.0.0.1', 65459)' w logach konsoli, wygląda jakby przerwał sesje po wywołaniu singleConvert(id_uuid), aplikacja odświeża główny template 'index.html' i chyba tworzy nową sesje bo generuje się kolejny token.

CSRF Token: Uly4w45VrN8TsPkCxCUokVvXPbSCMXEdbGg3yR4bufgWopVtRWzbDAKismYPtK0v
[02/Jan/2024 11:00:11] "GET / HTTP/1.1" 200 6064
[02/Jan/2024 11:00:11] "GET /static/converter/javascript/import.js HTTP/1.1" 304 0
Database UUID: 583bbf5c-625e-4e58-a6fa-b65c0721e183
Database UUID: 332fdc49-cf76-4332-8e24-ba57f77b1b33
Database UUID: c6b0103c-78f0-47b2-be57-f4fe4f04ac05
Database UUID: 36652700-4ba7-45a5-908d-01194735fbc0
Document Details: [{'success': True, 'file_name': '6668036303.pdf', 'uuid': '583bbf5c-625e-4e58-a6fa-b65c0721e183'}, {'success': True, 'file_name': '6671650937.pdf', 'uuid': '332fdc49-cf76-4332-8e24-ba57f77b1b33'}, {'success': True, 'file_name': '6675374903.pdf', 'uuid': 'c6b0103c-78f0-47b2-be57-f4fe4f04ac05'}, {'success': True, 'file_name': '6676040904.pdf', 'uuid': '36652700-4ba7-45a5-908d-01194735fbc0'}]
[02/Jan/2024 11:00:28] "POST /document_upload/ HTTP/1.1" 200 475
[02/Jan/2024 11:00:29,144] - Broken pipe from ('127.0.0.1', 65459)
CSRF Token: xWU0QEJVncfZuIdlyjuvtzyvY2mr4EopOhCZSrIbqEn2qiOcSD9iMeNQBdsELrKH
[02/Jan/2024 11:01:38] "GET /?csrfmiddlewaretoken=Uly4w45VrN8TsPkCxCUokVvXPbSCMXEdbGg3yR4bufgWopVtRWzbDAKismYPtK0v HTTP/1.1" 200 6064

Kod Javascript do wglądu, z góry dzięki za pomoc!

function singleConvert(id_uuid) {
    if (id_uuid) {
        console.log('Redirecting to:', `${window.location.origin}/document/${id_uuid}/`);
        window.location.href = `${window.location.origin}/document/${id_uuid}/`;
    } else {
        console.error('Invalid id_uuid. Unable to redirect.');
    }
}

function updateImportedFilesList(documents) {
    console.log('updateImportedFilesList(documents) executed with success', documents);

    var fileListHTML = '<ul>';

    documents.forEach(function (doc) {
        console.log('Document:', doc);
        fileListHTML += '<li>' +
            '<div class="file-info">' +
            '<span class="file-name">' + doc.file_name + '</span>' +
            '<button class="convert-btn" data-uuid="' + doc.uuid + '">Convert</button>' +
            '</div>' +
            '</li>';
    });

    if (documents.length >= 2) {
        fileListHTML += '<li>' +
            '<div class="convert-all-btn-container">' +
            '<button class="convert-all-btn" disabled>Convert All files into one CSV</button>' +
            '</div>' +
            '</li>';
    }

    fileListHTML += '</ul>';

    // Update the fileSelector div with the list of imported files
    uploadStatusContainer.innerHTML = fileListHTML;

    // Attach a click event listener to the closest common parent of the buttons
    var convertButtonsContainer = document.getElementById('uploadStatusContainer');

    convertButtonsContainer.addEventListener('click', function (event) {
        var targetButton = event.target.closest('.convert-btn');
        if (targetButton) {
            var id_uuid = targetButton.getAttribute('data-uuid');
            singleConvert(id_uuid);
        }
    });

    //Hide the label and file input after upload
    var uploadLabel = document.getElementById('selectButton');
    var uploadInput = document.getElementById('fileInput');

    uploadLabel.style.display = 'none';
    uploadInput.style.display = 'none';
}
1
bartnskey napisał(a):

Nie czaje o co chodzi bo uuid jak i token są prawidłowe do samego końca, dziwne jest to że adres URL zmienia się na local/token_csrf zamiast na local/document/uuid

Nie wiem, czy taka sytuacja jest możliwa, ale sprawdzałeś, czy przypadkiem Django nie tworzy dodatkowego przekierowania?

javascript pobiera prawidłowy uuid -> robi przekierowanie do /document/uuid/ -> django odpala swój kod, ale coś mu nie pasuje -> więc z prawidłowego adresu /document/uuid/ tworzy następne przekierowanie na crsf

0
Xarviel napisał(a):

Nie wiem, czy taka sytuacja jest możliwa, ale sprawdzałeś, czy przypadkiem Django nie tworzy dodatkowego przekierowania?

Przeglądam pliki ale nie widzę dodatkowego przekierowania

Klasa w models.py :

class Document(models.Model):
    id_uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    title = models.CharField(max_length=255)
    pdf_file = models.FileField(upload_to='uploaded/')
    created_at = models.DateTimeField(default=timezone.now)

Klasa w views.py odwołuje się do obiektu po zdefiniowanym w modelu id_uuid :

class DocumentPreviewView(View): 
    template_name = 'converter/document_preview.html'

    def get(self, request, id_uuid):
        # Retrieve the document with the given UUID
        document = Document.objects.get(id_uuid=id_uuid)
        
        # Render the document preview template with the document data
        return render(request, self.template_name, {'document': document})

Ścieżka w urls.py:

path('document/<uuid:id_uuid>/', views.DocumentPreviewView.as_view(), name='document_preview'),

2

Jednak to problem z javascriptem, funkcja singleConvert(id_uuid) wywoływała się asynchronicznie i przeglądarka jakby opuszczała bieżącą sesję zanim skończył się proces przekierowywania.
Dopiero jak wymusiłem inne zachowanie przycisku niż domyślne to poszło, tyle czasu zmarnować 🤬

function singleConvert(event, id_uuid) {
    if (id_uuid) {
        console.log('Redirecting to:', `${window.location.origin}/document/${id_uuid}/`);
        event.preventDefault();
        window.location.href = `${window.location.origin}/document/${id_uuid}/`;
    } else {
        console.error('Invalid id_uuid. Unable to redirect.');
    }
}
1

Aaaaa, dobrze rozumiem, że po prostu kliknięcie w przycisk wysyłało formularz i stąd potrzeba event.preventDefault()? Rano tego nie zauważyłem 😆

Zamiast event.preventDefault() możesz też dodać do przycisku atrybut type="button", <button type="button" class="..." data-uuid="...">...</button> i powinno zadziałać tak samo.

0

Dokładnie, 2 tygodnie nie mogłem znaleźć przyczyny już miałem ochotę zostawić to w pi*** :D

1 użytkowników online, w tym zalogowanych: 0, gości: 1