1

I've developed a form, using Bootstrap4, for create a blog post. This form is linked at a model in which there are two ForeignKey: a FileField and an ImageField.

If I use the default form rendering method({{ form.as_p }}) I can create a blog post but both the FileField and ImageField are rendered with the name of a single type of upload. I would like to see, instead of the name of the single image, the image. Then I've tried to use this:

<div class="form-group mb-4">
    <select class="form-control">
        {% for img in geoform.image %}
            <option value="{{ img.pk }}"> <img class="img-fluid" src="{{ img.path }}" alt="{{ img.name }}"> </option>
        {% endfor %}
    </select>
</div>

but I see an empty list. In the page source I see this:

<select class="form-control">
        <option value=""> <img class="img-fluid" src="" alt=""> </option>
        <option value=""> <img class="img-fluid" src="" alt=""> </option>
        <option value=""> <img class="img-fluid" src="" alt=""> </option>
        <option value=""> <img class="img-fluid" src="" alt=""> </option>
</select>

I've four objects inside the image model. For a reason that I don't understand the objects aren't rendered correctly.

This is the model:

class GeoBlogFile(models.Model):
    name = models.CharField(max_length=70)  
    path = models.FileField(upload_to='geoblog/documents/%Y/%m/%d')

    def __str__(self):
        return self.name

class GeoBlogImage(models.Model):
    name = models.CharField(max_length=70)  
    path = models.ImageField(upload_to='geoblog/images/%Y/%m/%d')

    def __str__(self):
        return self.name

class GeoBlog(models.Model):
    title = models.CharField(max_length=70, unique=True)
    slug_title = models.SlugField(max_length=70, unique=True)
    contents = models.TextField(max_length=200)
    file = models.ForeignKey(GeoBlogFile, on_delete=models.CASCADE, related_name="related_file", blank=True, null=True)
    image = models.ForeignKey(GeoBlogImage, on_delete=models.CASCADE, related_name="related_image", blank=True, null=True)
    publishing_date = models.DateTimeField(default=timezone.now, blank=True)
    geom = models.PointField(srid=3857)

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse("single_geopost", kwargs={"slug_title":self.slug_title})

This is the form:

class GeoBlogPostForm(forms.ModelForm):
    title = forms.CharField(
        max_length=70,
        widget=forms.TextInput(
            attrs={
                "placeholder": "Titolo",
                "type": "text",
                "id": "id_name",
                "class": "form-control form-control-lg",
                }
            ),
        )
    contents = forms.CharField(
        max_length=200,
        widget=forms.Textarea(
                attrs={
                    "placeholder": "Contenuti",
                    "type": "text",
                    "id": "id_contents",
                    "class": "form-control",
                    "rows": "2",
                    }
            ),
        )
    file = forms.ModelChoiceField(
        widget= forms.Select(
            attrs={
                "id": "id_file",
                "class": "custom-select",
                }
            ),
        empty_label="Select the file",
        queryset= GeoBlogFile.objects.all(),
        )
    image = forms.ModelChoiceField(
        widget= forms.Select(
            attrs={
                "id": "id_image",
                "class": "custom-select",
                }
            ),
        empty_label="Select the image",
        queryset= GeoBlogImage.objects.all(),
        )
    geom = forms.PointField(
        widget=forms.OSMWidget(
            attrs={
                'default_lat': 0,
                'default_lon': 0,
                'default_zoom': 2,
                }
            ),
        )
    publishing_date = forms.DateTimeField(
        widget=forms.DateTimeInput(
            attrs={
                "placeholder": "dd/mm/yyyy HH:MM:SS",
                "type": "text",
                "formats": "%m/%d/%Y %H:%M:%S",
                "id": "publishing_date_field",
                'class': 'form-control',
                'data-target': '#publishing_date_field',
                }
            ),
        )

    class Meta:
        model = GeoBlog
        fields = ['title', 'contents', 'file', 'image', 'publishing_date', 'geom']

The previous form-group is the last try of many. Is there a possibility to render an image list instead of the list of image's names?

MaxDragonheart
  • 1,117
  • 13
  • 34
  • 1
    `geoform.image` is a `BoundField`, the iterator returns the list of sub widgets. Replace your loop by `{% for img in geoform.fields.image.queryset %}` – dirkgroten Aug 27 '19 at 15:52
  • Ok, now in page source I can see pk, path and name but if I click on the form control I see still an empty list – MaxDragonheart Aug 27 '19 at 16:21
  • 1
    your image is an uploaded image, I'm pretty sure if you look further in your browser dev tools that you'll see 404 errors. The url of the image respective to your media url is `image.path.url` (that why calling a `FileField` `path` is not a good idea because it's not a path when you access it, it's a [`FieldFile`](https://docs.djangoproject.com/en/2.2/ref/models/fields/#filefield-and-fieldfile)) and to display it you need to prefix is with your MEDIA_URL (`{% get_media_prefix %}{{image.path.url}}`) – dirkgroten Aug 28 '19 at 08:27
  • Yes, I've already do this but I think that the solution of the second part of my problem is here https://stackoverflow.com/questions/2965971/how-to-add-images-in-select-list Thank you for your support. If you put your comment in an answer I will vote you – MaxDragonheart Aug 28 '19 at 08:56

1 Answers1

1

You're iterating through geoform.image, but that's the BoundField of the geoform. You're a bit unlucky, because it's a ChoiceField, iterating through it gives you the list of sub widgets, but it has nothing to do with the actual images.

To get the images, you must resort to the actual Field:

{% for img in geoform.fields.image.queryset %}

Also, make sure the url you use in your <img> tag is the proper prefixed media url for the uploaded file:

src="{% get_media_prefix %}{{ img.path.url }}"
dirkgroten
  • 20,112
  • 2
  • 29
  • 42