Django ImageField does not validate image - django

I can upload the code, however it is a very basic form that has an ImageField and a Model with and ImageField, however I can upload any file type. I have installed PIL and I am successfully writing the uploaded files to the media directory but as I stated, they can be whatever I like as no validation appears to be happening.
Update has been added, sorry I didn't do this earlier.
Views.
from django.shortcuts import render
from .forms import QuoteForm, ImageForm
from django.http import HttpResponse
from django.core.mail import EmailMessage
from django.shortcuts import redirect
from django.template.loader import get_template
from .models import Quote, Image, Job
from django.forms import modelformset_factory
from django.contrib import messages
from django.http import HttpResponseRedirect
def job_index(request):
jobs = Job.objects.all()
context = {
'jobs':jobs
}
return render (request, 'about.html', context)
def quote(request):
if request.method == 'POST':
form = QuoteForm(request.POST)
files = request.FILES.getlist('image')
if form.is_valid():
quote_form = form.save(commit=False)
quote_form.save()
messages.success(request, 'Form submission successful')
HttpResponse('image upload success')
form=QuoteForm()
for f in files:
Image.objects.create(quote=quote_form, image = f)
else:
print("Oh Know")
else:
form = QuoteForm()
context ={
'form': form,
}
return render (request, 'quote.html', context)
Form
from django import forms
from .models import Quote, Image
from django.core.exceptions import ValidationError
from django.core import validators
from django.utils.translation import gettext_lazy as _
import csv
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Field, ButtonHolder, Submit
SERVICES = [
('lawn', 'Lawn Mowing'),
('hedge', 'Hedge Triming'),
]
# def check_size(value):
# if len(value)<6:
# raise ValidationError("You fucked it")
class QuoteForm(forms.ModelForm):
title = forms.CharField(widget=forms.TextInput(attrs={"placeholder": "Post Code to check if we service your area"}))
message = forms.CharField(widget=forms.TextInput(attrs={"placeholder": "Title"}))
date_call = forms.CharField(widget=forms.TextInput(attrs={"id":"datetimes"}))
service = forms.ChoiceField(choices=SERVICES)
class Meta:
model = Quote
fields = ('title', 'message', 'email', 'date_call', 'service')
def clean_title(self):
with open("/Users/Mitch/Desktop/Work/Website/db_landscaping/db_landscaping/static/postcodes.csv", mode = "r") as csvDataFile:
csvReader = csv.reader(csvDataFile)
title = self.cleaned_data.get("title")
for row in csvReader:
if title not in row:
raise ValidationError('Postcode invalid or we do not service your area')
return title
class ImageForm(forms.ModelForm):
image = forms.ImageField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
class Meta (QuoteForm.Meta):
fields = QuoteForm.Meta.fields + ('image',)
Models
from django.db import models
from django.db.models.signals import pre_save
from db_landscaping import settings
import os
from django.template.defaultfilters import slugify
class Quote (models.Model):
title = models.CharField(null=True, max_length=100)
message = models.TextField(null=True,blank=True)
email = models.EmailField( null=True)
slug = models.SlugField(null=True ,unique=True )
service = models.CharField(max_length=100, null=True)
date_call = models.TextField(null=True)
created_date = models.DateTimeField(null=True, auto_now_add=True)
last_modified = models.DateTimeField(null=True, auto_now=True)
class Job (models.Model):
title = models.CharField(null=True, max_length=100)
message = models.TextField(null=True,blank=True)
image = models.ImageField(upload_to="images/job",null=True,blank=True)
class Image (models.Model):
quote = models.ForeignKey(Quote, default=None, on_delete=models.CASCADE)
image = models.ImageField(upload_to="images/",null=True,blank=True)
def __str__(self):
return self.quote.title + "Image"

Pretty sure am late here, but maybe in case anyone has the same issue, I think you would have had to create your own validator or use Djangos: Django.core.validators.validate_image_file_extension
and add this to your model field i.e
image = models.ImageField(upload_to="images/",null=True,blank=True, validators=[validate_image_file_extension])
That way, your uploaded files would be validated and incase there not an image, a validation error would be raised.

Related

Django get the current email of the user by default in a different serializer based on the selected "userid"

I was wondering what the correct way is to get the current email of the user by default in a different serializer based on the selected "userid".
I have tried many examples from the ModelSerializer docs but without success.
serializers.py
from rest_framework import serializers
from ticker.models import Ticker
from users.models import NewUser
from rest_framework.permissions import IsAuthenticated
from alerts.models import SectionAlerts
from users.serializers import UserlistSerializer
from rest_framework.fields import CurrentUserDefault
class TickerSerializer(serializers.ModelSerializer):
class Meta:
model = Ticker
fields = "__all__"
class UserlistSerializer(serializers.ModelSerializer):
class Meta:
model = NewUser
fields = "__all__"
class AlertsSerializer(serializers.ModelSerializer):
ticker = TickerSerializer(read_only=True)
email = UserlistSerializer(read_only=True)
ticker_id = serializers.SlugRelatedField(
queryset=Ticker.objects.all(), source="ticker", slug_field='crypto', write_only=True
)
class Meta:
model = SectionAlerts
fields = "__all__"
models.py
from django.db import models
from ticker.models import Ticker
from django.conf import settings
from import_export.resources import ModelResource
from import_export.fields import Field
from users.models import NewUser
from django.core.mail import EmailMessage
class SectionAlerts(models.Model):
id = models.AutoField(primary_key=True) # auto increment field
valuenow = models.FloatField(null=True, blank=True, default=None)
valuealarm = models.FloatField(null=True, blank=True, default=None)
user = models.CharField(max_length = 40,blank=True, null=True)
userid = models.ForeignKey(
NewUser, related_name='userid',
blank=True,
null=True,
on_delete=models.CASCADE,
)
email = models.ForeignKey(NewUser, blank=True, null=True, on_delete=models.CASCADE)
ticker = models.ForeignKey(Ticker, blank=True, null=True, on_delete=models.CASCADE)
The goal: anytime that the "Current Value" of a crypto is lower than the previously set "Value Alert", the backend is sending an email notification to the user.
The problem: at the moment all users receive that email notification, while just each individual logged in user that created
their own alerts should receive it.
Question: how can i add just the email of the user that created the individual alert?
views.py
from email import message
from rest_framework import generics
from rest_framework import status
from .serializers import AlertsSerializer, TickerSerializer, UserlistSerializer
from users.serializers import CustomUserSerializer
from .models import SectionAlerts, Ticker, NewUser
import requests
import logging
from itertools import chain
from importlib import reload
import sys
import csv
from django.http import HttpResponse
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.settings import api_settings
from rest_framework.response import Response
from .utils import Util
from django.urls import reverse
from django.shortcuts import redirect
class CreateSectionAlerts(generics.CreateAPIView):
def perform_create(self, serializer):
serializer.save(user=self.request.user)
print("New alert is saved")
serializer_class = AlertsSerializer
class ListSectionAlerts(generics.ListAPIView):
queryset = SectionAlerts.objects.all()
serializer_class = AlertsSerializer
# ------- EMAIL STARTS HERE
def get_queryset(self):
print("****ALERTS START get_querysetdavid")
queryset = SectionAlerts.objects.filter(userid=self.kwargs["pk"])
for b in SectionAlerts.objects.filter(userid=self.kwargs["pk"]):
# print("b---Print just mail", b.email)
print("b---Print SectionAlerts", b.id, b.valuenow, b.userid, b.ticker.c_0)
for c in NewUser.objects.all():
if b.ticker.c_0 < b.valuealarm:
print("Alert is achieved and must be sent")
email_body = 'Hi ' + c.user_name + ', you received this message because the value of the crypto ' + str(b.ticker) + ' is now ' + str(b.ticker.c_0) +'€.' + ' and reached the alert value of ' + str(b.valuealarm) +'€.' + '\n'+ 'This email confirms this event. \n' + 'Click here https://www.cryptothlon.com to signin in your account and know more. \n' +'\n'+ 'Your Cryptothlon Team'
data={'email_body': email_body, 'to_email': c.email,
'email_subject': 'Crypto alert'}
Util.send_email(data)
print("Email sent")
try:
record = SectionAlerts.objects.get(id = b.id )
record.delete()
print("Record deleted successfully!")
except:
print("Record doesn't exists")
# email method ends here
return queryset
# ------- EMAIL ENDS HERE
class DeleteSectionAlerts(generics.RetrieveDestroyAPIView):
queryset = SectionAlerts.objects.all()
serializer_class = AlertsSerializer
You can use SerializerMethodField. It will allow you to create a custom field in the serializer. By default SerializerMethodField looks for a method get_<field name>, and performs the according logic:
from users.models import NewUser
class AlertsSerializer(serializers.ModelSerializer):
...
email = serializers.SerializerMethodField()
class Meta:
model = SectionAlerts
fields = "__all__"
def get_email(self, obj):
user_id = self.initial_data['userid'] # get the `userid` from the request body
user = NewUser.objects.get(pk=user_id) # fetch the user from DB
return UserlistSerializer(instance=user).data
You don't show the NewUser model so not sure exactly what field you need, but you can use dot notation for the source of a serializer field.
From DRF docs:
The name of the attribute that will be used to populate the field. May be a method that only takes a self argument, such as URLField(source='get_absolute_url'), or may use dotted notation to traverse attributes, such as EmailField(source='user.email').
See this section of the docs: https://www.django-rest-framework.org/api-guide/fields/#core-arguments

Django Foreign Key model cant display in view JSON

When I run this, I get JSON file but the foreign key (contact numbers) are not included, I want to display one contact name/address/email with multiple contact numbers.
models.py
from django.db import models
class PhoneBook(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=100, default='address')
email = models.CharField(max_length=50, default='email')
note = models.CharField(max_length=100, default='note')
def __str__(self):
return self.name
class ContactNumber(models.Model):
number = models.ForeignKey(PhoneBook, related_name="contact_numbers")
contact_number= models.CharField(max_length=30)
def __str__(self):
return self.contact_number
views.py
from django.shortcuts import render
from .models import PhoneBook,ContactNumber
from django.http import JsonResponse
from django.views import View
class PhoneBookList(View):
def get(self,request):
phonebooklist=list(PhoneBook.objects.values())
return JsonResponse(phonebooklist,safe=False)
admin.py
from django.contrib import admin
from .models import PhoneBook,ContactNumber
class ContactNumberInline(admin.StackedInline):
model = ContactNumber
class PhoneBookAdmin(admin.ModelAdmin):
inlines =[
ContactNumberInline,
]
admin.site.register(PhoneBook)
admin.site.register(ContactNumber)
RESULT:
enter image description here
I might be able to answer with this approach.
class PhoneBook(models.Model):
....
def to_json(self):
contact_numbers = [c.contact_number
for c in self.contact_numbers.all()]
return {
'name': self.name,
'email': self.email,
'address': self.address,
'note': self.note,
'contact_numbers': contact_numbers
}
In your view.
class PhoneBookList(View):
def get(self,request):
phonebooklist = PhoneBook.objects.all()
serialized_data = [pb.to_json() for pb in phonebooklist]
return JsonResponse(serialized_data, safe=False)
A bit dirty solution though

Having problems with a query in Django

I'm building my first app within Django and I'm trying to query a "load" based on the company that i've attached to the load. Here's the model in question.
class Load(models.Model):
company = models.ForeignKey(UserCompany, null=True,
on_delete=models.CASCADE)
load_number = models.IntegerField()
carrier = models.CharField(max_length=255)
pickup_date = models.DateField()
delivery_date = models.DateField()
shipper = models.CharField(max_length=255)
consignee = models.CharField(max_length=255)
po_number = models.CharField(max_length=255)
pu_number = models.CharField(max_length=255)
pieces = models.IntegerField()
description = models.TextField()
date_created = models.DateTimeField(blank=True, null=True)
def publish(self):
self.date_created = timezone.now()
self.save()
def __str__(self):
return str(self.load_number)
Now I'm trying to display a list on a page, but only display the loads attached to a specific company. The user needs to be attached to that company as well so here are my user models.
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class UserCompany(models.Model):
company_name = models.CharField(max_length=200)
def __unicode__(self):
return self.company_name
def __str__(self):
return self.company_name
# User Model
class UserProfileInfo(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
# Additional Classes
profile_pic = models.ImageField(upload_to='profile_pics',
blank=True)
company = models.ForeignKey(UserCompany,
null=True,on_delete=models.CASCADE)
def __str__(self):
return self.user.username
Then i'm trying to query the "loads" within this view.
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.shortcuts import render, get_object_or_404
from django.shortcuts import redirect
import datetime
from django.conf import settings
from django.utils import timezone
from django.http import HttpResponse
from django.views.generic import View, DetailView
from easy_pdf.views import PDFTemplateResponseMixin
from loads.models import Load
from .forms import LoadForm
from users.models import UserCompany, UserProfileInfo
# Create your views here.
class PDFUserDetailView(PDFTemplateResponseMixin, DetailView):
model = Load
template_name = 'loads/load_pdf.html'
def load_list(request):
loads =
Load.objects.filter(company=request.company).order_by('date_created')
return render(request, 'loads/load_list.html', {'loads':loads})
I was able to get the query working based on the user, so my thought is that this query would be the same. This is not the case. I have a feeling that i'm referencing company wrong and maybe I somehow need to filter 2 more levels down all the way to the original UserCompany class, just not sure how to accomplish that.
The error that i'm getting is:
AttributeError: 'WSGIRequest' object has no attribute 'company'
request.company isn't a thing you can do. Instead of
Load.objects.filter(company=request.company).order_by('date_created')
You try something like this:
current_user = request.user
company = current_user.userprofileinfo.company
Load.objects.filter(company=company).order_by('date_created')
request just holds information about the current request which you can read more about here

Is_valid method return false in the second time using

I write the unittest for my post function,but in the second time,It's always fail.here is my forms.py
from django import forms
from django.contrib.auth.models import User
from django.utils import timezone
from models import Post
class PostForm(forms.ModelForm):
class Meta:
model = Post
here is my models.py
from django.db import models
from django.contrib.auth.models import User
class Post(models.Model):
post_author = models.ForeignKey(User)
created_at = models.DateTimeField()
update_at = models.DateTimeField()
post_title = models.TextField(blank=True)
activity_address = models.TextField(blank=True)
post_content = models.TextField()
post_type = models.CharField(max_length=50, choices=[('activity', 'activity', ), ('blog', 'blog')])
post_status = models.CharField(max_length=50, choices=[('open', 'open'), ('locked', 'locked') ])
here is the postlib.py
from models import Post
from forms import PostForm
from django.utils import timezone
def create(data):
if not data['created_at']:
data['created_at'] = timezone.now()
if not data['update_at']:
data['update_at'] = timezone.now()
post_form = PostForm(data=data)
if post_form.is_valid():
post = post_form.save()
else:
post = None
return post
and the unittest code
from django.test import TestCase
from django.utils import timezone
from Publish.forms import PostForm
from Publish.models import Post
from Publish import postlib
from django.contrib import auth
from django.contrib.auth.models import User
class PublishTest(TestCase):
def setUp(self):
User.objects.create_user(username='test', email='test#test.com', password='abc')
self.user = auth.authenticate(username="test", password='abc')
self.data = {'post_author': '1',
'post_title': 'test',
'post_content': 'nothing',
'activity_address': 'New York',
'created_at': '',
'update_at': '',
'post_type': 'activity',
'post_status': 'open'}
def test_a(self):
post = postlib.create(self.data)
self.assertNotEqual(post, None)
def test_b(self):
post = postlib.create(self.data)
self.assertNotEqual(post, None)
In the unittest,It always have a failure,either test_a or test_b,and the reason of failure is the form.is_valid(). the Is_valid() method will fail sometime,but I use the same data,How can it be?
PS:the post_form error is
'Select a valid choice. That choice is not one of the available choices.'

Question On Django Form Models

I am working on form models and get this error:
global name 'AdForm' is not defined
In my view I have:
from django.template import RequestContext, loader
from django.http import HttpResponse
from django.shortcuts import redirect
from django.contrib.auth.decorators import login_required
from django import forms
#login_required
def create(request):
if request.POST:
ad = AdForm(request.POST)
if ad.is_valid():
test = 'valid'
else:
test = 'invalid'
else:
test = 'none'
template = loader.get_template('ads/create.html')
context = RequestContext(request, {
'test': test
})
return HttpResponse(template.render(context))
However it is not picking up my model. My model in my view is:
from django.db import models
from django.forms import ModelForm
TYPE_CHOICES = (
'Image',
'Code',
)
SIZE_CHOICES = (
'Leaderboard',
'Banner',
'Skyscraper',
'Square',
)
class Ad(models.Model):
title = models.CharField(max_length=40)
type = models.CharField(max_length=7)
size = models.CharField(max_length=16)
clicks = models.IntegerField()
media = models.ImageField(upload_to='ads')
link = models.URLField(null=True)
created = models.DateTimeField(auto_now_add=True)
expires = models.DateTimeField(null=True)
def __unicode__(self):
return self.name
class AdForm(ModelForm):
class Meta:
model = Ad
Does anyone know why it is not picking up the form model?
Thanks from a noob.
At the top of your view, you need:
from .models import AdForm
Also, forms usually go in forms.py, not with the models.