Question

I have built a wizard in my project. In the first step I create an object "Building" and save it in the db. In the second step I let the user upload an image of the building saved in the first step.

The image is in the Building's model.

When I try to customize the saving path of the image, I found out that "instance.pk" is None.

The same thing happen if I try to access every attribute of the Model that should be in "instance". The only attributes that I can access are those I manually set in the View (ex. nome, descrizione, ...)

I don't undersant why is happening this. Could somebody explain it to me?

Part of the Model:

 class Building(models.Model):
    utente = models.ForeignKey(User);
    nome = models.CharField(max_length=200, unique=True)
    descrizione = models.TextField(max_length=1000, blank=True)
    link = models.URLField(blank=True)
    foto = ImageField(upload_to=content_file_name, blank=True)
    ...

Content_file_name:

 def content_file_name(instance, filename):         
    estensione = '.jpg'       
    posizione_punto = filename.rfind('.')        
    if posizione_punto > 0:
            estensione = filename[posizione_punto:]
    return '/'.join(['buildings', str(instance.pk), 'vetrina'+estensione])

Part of the View (2nd wizard step):

 # I load the building from the db
 building = get_object_or_404(Building, pk=b_id)

 if request.method == 'POST':

       form = StepOneForm(request.POST, request.FILES)
       if form.is_valid():
            data = form.save(commit=False)
            building.data_update = datetime.datetime.now()
            building.nome = data.nome
            building.descrizione = data.descrizione
            building.link = data.link
            building.foto = data.foto

            building.save()

            ...
Was it helpful?

Solution

Firstly, you've defined your foto field as foto = ImageField() it should probably be foto = models.ImageField()

Secondly, when you initiate your form you're not including the instance argument (have a look at the docs). It should be something like -

form = StepOneForm(request.POST, request.FILES, instance=building)

That's how django knows to add the html form data to an existing instance. If you declare your form like this -

from django.forms import ModelForm

class BuildingForm(ModelForm):
    class Meta:
        model = Building

Then when you do data = form.save(commit=False) your data variable is actually an instance of Building. And if you've already said that the form relates to a specific instance (eg the building you declare at the beginning of your view), then data will be that specific instance of Building.

This means that you can change your view code to -

def your_view(request):
    building = get_object_or_404(Building, pk=b_id)
    if request.method == 'POST':
        form = BuildingForm(request.POST, request.FILES, instance=building)
           if form.is_valid():
               building = form.save(commit=False)
               building.save()
    else: #...

Have a look at the Form and ModelForm Docs.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top