Django CreateView 允许在点击后退按钮时显示表单时重新提交数据

Django CreateView allows resubmission of the data when the form is displayed when hiting the back button

我正在尝试制作一个带有上传图片的应用。问题是我想将上传图像的可能性限制为每天一次。一切正常,除非用户使用浏览器的后退按钮。他可以向系统发送垃圾邮件。防止这种情况的正确方法是什么?

models.py

# Admin option to select from
PHOTO_STATUS = (
    ('ir', 'In Review'),
    ('ap', 'Approved'),
    ('tr', 'Trash'),
)

def pause():
    return timezone.now() + timezone.timedelta(minutes=5)


# Main photo upload app
class PhotoUpload(models.Model):
    '''After the user finishes the challenge
    he can upload a photo using this app'''
    # The date when a user uploads a photo
    date_upload = models.DateTimeField(default=timezone.now)
    # The date when user can upload another photo

    # pause = date_upload + timezone.timedelta(minutes=20)
    pause_upload = models.DateTimeField(default=pause)
    # The status of the photo
    status = models.CharField(max_length=2, default='ir', choices=PHOTO_STATUS)
    # The date when the admin aproves the photo
    date_approved = models.DateTimeField(default=timezone.now,
                                         blank=True,
                                         null=True)
    # The date when the admin soft-deletes the photo
    date_deleted = models.DateTimeField(default=timezone.now,
                                        blank=True,
                                        null=True)
    user = models.ForeignKey(User)

    # A function that defines the path where the photo
    # will be uploaded and that will change the filename.
    def path_and_rename(instance, filename):
        extension = filename.split('.')[-1]
        if User.is_authenticated:
            # print(instance._user.username)
            return 'uploads/{}-{}.{}'.format(instance.user.username,
                                             instance.date_upload,
                                             extension)
        else:
            return 'uploads/{}.{}'.format(instance.date_upload, extension)

    # Application side file size check
    def file_size(value):
        limit = 2 * 1024 * 1024
        if value.size > limit:
            raise ValidationError(
                'File too large. Size should not exceed 2 MB.')

    image = models.ImageField(upload_to=path_and_rename,
                              validators=[file_size],
                              null=True,
                              blank=True)

    def __str__(self):
        return str(self.pause_upload)

查看

class PhotoUploadCreate(CreateView):
    model = PhotoUpload
    template_name = 'upload_photo.html'
    form_class = PhotoUploadForm

    def form_valid(self, form):
        form.instance.user = self.request.user
        return super(PhotoUploadCreate, self).form_valid(form)

    def get_success_url(self):
        return reverse('success')

谢谢!

编辑 这是我的模板,我在其中使用了一个名为 photos 的模板标签和一个名为 elapsed.

的模板过滤器
{% for photo in photos %}

    <div class="container vertical-centre">

        {% if not photo.pause_upload|elapsed:1 %}

            <div class="row">
                <div class="col-md-8 col-md-offset-2">
                    <h1 class="centre-colour">
                        {% if photo.user.first_name %}{{ photo.user.first_name }}{% else %}{{ photo.user.username }}{% endif %} you can upload another photo anytime after:<br>
                            <div id="clockdiv" class="centre-colour">
    <span class="hours"></span> Hours <span class="minutes"></span> minutes 
    <span class="seconds"></span> seconds
</div>
                    </h1>
                </div>
            </div>

        {% else %}

            <div class="row">
                <div class="col-md-8 col-md-offset-2">
                    <h1 class="centre-colour">
                        CONGRATULATIONS {% if photo.user.first_name %}{{ photo.user.first_name }}{% else %}{{ photo.user.username }}{% endif %}!!!
                    </h1>
                    <h2 class="centre-colour">
                       Upload photo:
                    </h2>
                </div>
            </div>

            <div class="row">
                <div class="col-md-8 col-md-offset-2">  
                    <form action="" method="POST" enctype="multipart/form-data">
                    {% csrf_token %}
                        <div class="form-group">
                        {% crispy form %}
                        </div>
                    </form>
                    <h4 class="centre-colour">or</h4>
                    <a href="{% url 'home' %}" role="button" id="goHome" class="btn btn-primary btn-block">Start again</a>
                </div>
            </div>

        {% endif %}
    </div>
{% endfor %}

这里是模板标签和过滤器

register = template.Library()
@register.inclusion_tag('photos/photos_tags.html')
def photos_up(request, number=1):
    a = PhotoUpload.objects.filter(user__username=request).exists()
    if a:
        return {'form': PhotoUploadForm(),
                'photos': PhotoUpload.objects.filter(
                    user__username=request
        ).order_by(
                    '-pause_upload')[:number]
        }
    else:
        return {'form': PhotoUploadForm(),
                'photos': PhotoUpload.objects.all()[:number]
                }

register = template.Library()
@register.filter(expects_localtime=True)
def elapsed(time, seconds):
    return time + timezone.timedelta(seconds=seconds) < timezone.now()

除非用户决定从 成功 页面点击后退按钮,否则一切正常。然后 上传 页面将再次进入表单视图,而不是转到柜台。

您可以将属性作为 lastuploaded (DateTimeField) 放入数据库中,当用户上传照片时检查 lastuploaded 是否比当前时间早一天。 编辑: 将 lastuploaded 字段添加到您的模型。

class PhotoUpload(models.Model):
    last_uploaded = models.DateTimeField(null=True, blank=True, default=timezone.now)

现在在您视图的 form_valid 函数中进行检查。

def form_valid(self, form):
        photo_upload_object = PhotoUpload.objects.filter(user=self.request.user).latest('last_uploaded')
        if photo_upload_object.last_uploaded + datetime.datetime.timedelta(days=1) < current_time and photo_upload_object.last_uploaded is not None:
            form.instance.user = self.request.user
            return super(PhotoUploadCreate, self).form_valid(form)
        else: 
            return HttpResponse("some error")

其他方法可能是将上次上传的内容保存在 cookie 中,但这并不适用于所有情况,例如从不同设备登录。