Check id of foreign key object - django

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:

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

Instantiating a ModelForm with initial values in CBVs

I am a Django newbie working with Django CBVs and having difficulty setting initial values for my ModelForm. To give an overview, I am trying to learn by creating a simple messaging app.
Here is my code:
models.py
import datetime
from django.contrib.auth.models import User
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.utils import timezone
class Message(models.Model):
subject = models.CharField(_("Subject"), max_length=100)
body = models.TextField(_("Body"))
sender = models.ForeignKey(User, db_index=True, related_name='sent_messages')
recipient = models.ForeignKey(User, db_index=True, related_name='received_messages')
parent_msg = models.ForeignKey('self', related_name='next_messages', null=True, blank=True)
forms.py
from django.forms import ModelForm
from .models import Message
class MessageForm(ModelForm):
class Meta:
model = Message
exclude = ('sender', 'recipient', 'parent_msg',)
views.py
class MessageCreateView(CreateView):
form_class = MessageForm
model = Message
template_name = 'messages/compose.html'
def form_valid(self, form):
form.instance.sender = self.request.user
return super(MessageCreateView, self).form_valid(form)
urls.py
...
url(r'^compose/(?P<recipient>[\w.#+-]+)/$', MessageCreateView.as_view(), name='messages_compose_to'),
...
As you can see from the urls.py file, I am using the 'recipient' parameter as such: http://localhost:8000/members/compose/someusername
Now my problem is that I wish to open the compose message view, and initialize the recipient field by getting the username from the URL, then using the username from the url to get User with that particular username, and instantiate the form with it.
Where do I do this, in the view itself or in the form? Unless their is a better way of how to handle this.
You can add get_initial() method to return appropriate dict, something as below.
class MessageCreateView(CreateView):
...
def get_initial(self):
data = { 'recipient':
User.objects.get(username=self.kwargs.get('recipient'))
}
return data
Handle error appropriately.

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.