Home > Mobile >  upload a file while having a one to one relationship in django
upload a file while having a one to one relationship in django

Time:06-14

sorry for all the code given but i have tried so hard for a day still ending up with a problem when passing stage_id as a parameter in the form action url

I have a class Rapports that holds a file (i prefer pdf files) and have a 1to1 relationship with an other class from an other application, i'm sending the stage.id from a html page in Stages app and it's working the id is passed and i can pass it to an other html page but when i write the code i need and passe the same url pattern in the action attribute of the template i want to show(rapport/test.html down below) it return NoReverseMatch and i can't figure out why. Is it because i'm trying to upload a file or is it something else? (1st time working with files)

{% block rpt %}
    <li >
        <a  href="{% url 'rapport:depo' stages.id %}">
            déposer le rapport
        </a>
    </li>
{% endblock rpt %}

rapport.Rapports

from django.db import models

from satges.models import Stages

class Rapports(models.Model):
    stage=models.OneToOneField(
        Stages,
        on_delete=models.CASCADE,
        primary_key=True,
    )
    src=models.FileField(
        ("rapport"),
        upload_to='rapports/',
        max_length=100
    )
    r_soummit=models.DateTimeField(
        auto_now=False,
        auto_now_add=False,
    )

satges.Stages

class Stages(models.Model):
    #Stages attrs that are saved so i think no need to show them here

    def est_ete(self):
        # comment: this fn returns true if it's a summer intership
        if(self.deb.month in[6,7,8]):
            return True
    # end def
    def get_absolute_url(self):
        return reverse("satges:det_stg", kwargs={"pk": self.pk})
#saving Stages to database with CreateView is working
    def __str__(self):
        return self.etd   ' '   self.nature   " - "   self.au

rapport.forms.py

from django import forms

from .models import Rapports

class RapportsForm(forms.ModelForm):
    class Meta:
        model = Rapports
        fields = ['src']
        
        widgets = {
            'src': forms.FileInput(),
        }

rapport.views

from django.http import HttpResponse
from django.shortcuts import get_object_or_404, render
from django.views.generic import CreateView
from satges.models import Stages
from .models import Rapports
from .forms import RapportsForm

# Create your views here.

def afficher(request, stage_id):
    # comment: 
    #return HttpResponse('stage: %s'% stage_id)
    if request.method == 'POST':
        form = RapportsForm(request.POST, request.FILES)
    else:
        form=RapportsForm()
    return render(request, 'rapport/test.html', {'form': form})

class RapportCreateView(CreateView):
    model = Rapports
    form_class=RapportsForm
    template_name = "rapport/test.html"


# end def
'''
def afficher_depo(request, stage_id):
    form=RapportsForm()
    print(stage_id)
    return render(request,'rapport/depo.html', {'form': form})

def depo(request, stage_id):
    if request.method == 'POST':
        form = RapportsForm(request.POST)
        stage=get_object_or_404(Stages, pk=stage_id)
        src = form.cleaned_data['src']
        rpt=Rapports(stage=stage,src=src)
        rpt.save()
    else:
        return HttpResponse('rapport isn\'t saved')
    
    return render(request,'rapport/depo.html', {'form':form})
    '''

the project url conf

from django.contrib import admin
from django.urls import include, path
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('satges.urls')),
    path('journal/', include('journaux.urls')),
    path('rapport/<int:pk>', include('rapport.urls')),
]  static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

rapport.urls.py

from django.urls import path, re_path
from . import views

app_name = 'rapport'
urlpatterns = [
    path('',views.RapportCreateView.as_view(), name='depo'),
]

test.html (this file is just for testing the main file is called depo.html and it extends otthe page and have the same behavior when i remove the url in action the form appears)

<html>
  <head>
    <title>test</title>
  </head>
  <body>
    <form method="post" enctype="multipart/form-data" action="{% url 'rapport:depo' satge_id %}">
      <!--when i remove the url tag the input form appears and i can choose a file but i ofc can't send it without the action-->
        {% csrf_token %}
        {{ form.as_p }}
    <input type="submit" value="déposer votre rapport" name="depo">
    </form>
  </body>
</html>

this should be all the code related to the problem, i have tried googling, youtube, django doc and with the changes i made along the day the errors differed but the one i couldn't get through is NoReverseMatch

error

Error during template rendering

In template /home/ssoya/Documents/pfe/new/pages/templates/rapport/test.html, error at line 6
Reverse for 'depo' with arguments '('',)' not found. 1 pattern(s) tried: ['rapport/(?P<pk>[0-9] )\\Z']

after the 1st answer my view became like this but no matter i change it still no use

class RapportsCreateView(CreateView):
    model = Rapports
    form_class=RapportsForm
    template_name = "rapport/depo.html"

    def get_context_data(self, **kwargs):
        context=super(RapportsCreateView, self).get_context_data(**kwargs)
        #stage=Stages.objects.get(pk=self.kwargs.get('pk'))
        context['stages'] = Stages.objects.filter(pk=self.kwargs.get('pk'))
        return context

then i tried something else: I replaced stage.id with 1 then 13 to see what happens. It raised IntegrityError

NOT NULL constraint failed: rapport_rapports.stage_id
The above exception (NOT NULL constraint failed: rapport_rapports.stage_id) was the direct cause of the following exception:
response = get_response(request)

i'm willing to restructure the question once i found a soloution or understand it more

CodePudding user response:

it's because of stage_id as it's not defined so url will not be found as it needs the parameter stage_id, check the view that rendering your template it is not retuning the stage_id variable
add this to your create view

def get_context_data(self, **kwargs):
        # Call the base implementation first to get a context
        context = super().get_context_data(**kwargs)
        # context is a dict so 
        #update it with your stage id
        return context

in this function add the stage_id so it get passed to the template

CodePudding user response:

i can say it is 90% Solved

the problem i had in this question was related to the context in my view and after the answer of @mohamed and some googling and tries i made the view ended up working and saving the file to the server and the database and putting the id of the Satges object as the id of rapport as the attribute satge_id then redirects the user to an other page

here are the modifications i made

views.py

class RapportsCreateView(CreateView):
    model = Rapports
    form_class = RapportsForm
    template_name = "rapport/depo.html"

    def form_valid(self, form):
        self.stage_id = self.kwargs['pk']
        stage = Stages.objects.get(id=self.stage_id)
        form.instance.stage_id = stage.id
        form.instance.r_soummit = timezone.now()
        return super().form_valid(form)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        stage = Stages.objects.get(pk=self.kwargs.get('pk'))
        context['stage'] = stage
        context['stage_id'] = stage.id
        return context

models.Rapports

def get_absolute_url(self):
        return reverse("rapport:det_rpt", kwargs={"pk": self.pk})

def __str__(self):
        return self.src
  • Related