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
Related
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
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.
I have exhausted all avenues in trying to put together a solution for this, but my current knowledge of Python and Django can only get me so far.
I'm creating a basic ticketing system and CreateView used to work until I created a Profile model and then separated the Ticket model into its own app. There were already a couple of tickets created when I refactored my code which is why I know ListView works, DeleteView works as well as DetailView. CreateView works until I hit the save button.
My views and models are below; I hope someone can please help me sort this out.
Ticket Model
from django.db import models
from django.contrib.auth.models import User
....
from qcapp.models import Profile
class Ticket(models.Model):
# Relations
user = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name="tickets", verbose_name="user")
# Attributes
title = models.CharField(max_length=250, verbose_name="Title", help_text="Enter a Ticket Title")
color = models.CharField(max_length=7,
default="#ffffff",
validators=[RegexValidator("(^#[0-9a-fA-F]{3}$)|(^#[0-9a-fA-F]{6}$)")],
verbose_name="Color",
help_text="Enter the hex color code, like #ccc or #cccccc")
description = models.TextField(max_length=1000)
created_date = models.DateTimeField(default=timezone.now, verbose_name='Created Date')
created_by = models.ForeignKey(User, related_name='created_by_user')
# Attributes
# Object Manager
objects = managers.ProjectManager()
# Meta and String
class Meta:
verbose_name = "Ticket"
verbose_name_plural = "Tickets"
ordering = ("user", "title")
unique_together = ("user", "title")
def __str__(self):
return "%s - %s" % (self.user, self.title)
def get_absolute_url(self):
return reverse('ticket_detail', args=[str(self.id)])
Ticket View (CreateView Only)
# -*- coding: utf-8 -*-
...
from django.views.generic import CreateView, UpdateView, DeleteView
...
from .models import Ticket
...
class TicketCreate(CreateView):
model = Ticket
template_name = "tickets/ticket_form.html"
fields = ['title', 'description']
def form_valid(self, form):
form.instance.created_by = self.request.user
return super(TicketCreate, self).form_valid(form)
...
Profile Model(Imported Into Ticket Model)
from django.db import models
from django.conf import settings
from django.contrib.auth.models import User
from django.dispatch import receiver
from django.db.models.signals import post_save
from . import managers
class Profile(models.Model):
# Relations
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="profile", verbose_name="user")
# Attributes
interaction = models.PositiveIntegerField(default=0, verbose_name="interaction")
# Attributes
# Object Manager
objects = managers.ProfileManager()
# Custom Properties
#property
def username(self):
return self.user.username
# Methods
# Meta and String
class Meta:
verbose_name = "Profile"
verbose_name_plural = "Profiles"
ordering = ("user",)
def __str__(self):
return self.user.username
#receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_profile_for_new_user(sender, created, instance, **kwargs):
if created:
profile = Profile(user=instance)
profile.save()
It looks like you need to add the following to your TicketCreate class in the form_valid function:
form.instance.user = Profile.objects.get(user=self.request.user)
Let me know if that works!
I have created this simple model:
from django.db import models
from slugify import *
class News(models.Model):
title = models.CharField(max_length=100)
body = models.TextField()
pub_date=models.DateTimeField(auto_now_add=True)
likes = models.IntegerField(default=0)
visits = models.IntegerField(default=0)
slug = models.SlugField()
status = models.BooleanField(default=True)
#approved = models.BooleanField(default=False)
def __unicode__(self):
return unicode(self.title)
def save(self, *args, **kwargs):
self.title = slugify(self.title)
super(News, self).save(*args, **kwargs)
admin.py
from django.contrib import admin
from news.models import News
admin.site.register(News)
Whenever I create a news content in the admin panel with a Persian title, the title does not display on the panel. When the title is in ascii characters, there is not such problem
My Django version is 1.5.5 and mysql database is utf8. I've added this to settings.py (though not sure it is relevant!)
from __future__ import absolute_import, unicode_literals
So appreciate your hints.
I expect the problem is that you're using the slugify function, which explicitly strips out non-ASCII characters.
I'm not sure why you want to slugify the title in the first place, but you might want to look into the new awesome-slugify library, which deals correctly with those characters.
Im trying to write a function to check that the user has correct member category.
My models:
from django.db import models
from django.contrib.auth.models import User
class Membercategory(models.Model):
membercatname = models.CharField(max_length=200)
class Profile(models.Model):
user = models.OneToOneField(User)
mobilephone = models.CharField(max_length=12, blank=True)
membercategory = models.ForeignKey(Membercategory, blank=True, null=True)
My user-check middleware:
from django.http import HttpResponseRedirect
from django.conf import settings
class UserCheckMiddleware:
def process_request(self, request):
invalid_user_path = settings.INVALID_USER_URL
if request.user.is_authenticated() and not request.user.is_staff:
if not request.user.profile.membercategory(id=426):
return HttpResponseRedirect(invalid_user_path)
else:
return
The error I get is: Membercategory object is not callable
How should I do the check?
Well, as the error says, Django model instances are not callable. You just want a simple comparison to the ID:
if request.user.profile.membercategory_id != 426: