Here is my model
Model
from Account.models import User
from django.db import models
class Seller(models.Model):
seller = models.OneToOneField(User, on_delete = models.CASCADE)
email = models.EmailField(max_length = 90, unique = True)
country = models.CharField(max_length = 60)
phone = models.CharField(max_length= 20, unique = True, blank = True, null = True)
address = models.TextField()
zipcode = models.CharField(max_length = 10)
form
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.db import transaction
from .models import Seller
from Account.models import User
class SellerCreationForm(UserCreationForm):
name = forms.CharField(required = True)
email = forms.EmailField(required = True)
phone = forms.CharField(required = False)
country = forms.CharField(required = True)
address = forms.CharField(required = True)
zipcode = forms.CharField(required = True)
class Meta(UserCreationForm.Meta):
model = User
#transaction.atomic
def save(self):
user = super().save(commit=False)
user.is_seller = True
user.name = self.cleaned_data.get('name')
user.save()
seller = Seller.objects.create(user=user)
seller.email = self.cleaned_data.get('email')
seller.phone = self.cleaned_data.get('phone')
seller.country = self.cleaned_data.get('country')
seller.address = self.cleaned_data.get('address')
seller.zipcode = self.cleaned_data.get('zipcode')
seller.save()
return user
views
from django.shortcuts import render, redirect
from django.views.generic import CreateView
from .forms import SellerCreationForm
from django.contrib.auth.forms import AuthenticationForm
from Account.models import User
class RegisterSeller(CreateView):
model = User
form_class = SellerCreationForm
template_name = 'registration/registerseller.html'
def form_valid(self, form):
user = form.save()
login(self.request, user)
return redirect('/')
I tried to create a project with multiple users types and all users having different functionality.
Everything in the code functions well but whenever I try to register a new user I get an error.
And it says Seller() got an unexpected keyword argument 'user'
The ForeignKey from the Seller to the User has been named seller, not seller`. You thus can construct an object with:
seller = Seller.objects.create(
seller=user,
email=self.cleaned_data['email']
phone = self.cleaned_data['phone']
country = cleaned_data['country']
address = self.cleaned_data['address']
zipcode = self.cleaned_data['zipcode']
)
But perhaps it is better to rename the field to:
from Account.models import User
from django.db import models
class Seller(models.Model):
user = models.OneToOneField(User, on_delete = models.CASCADE)
# ⋮
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.
Related
I am just starting with Django and web development , so please be nice with me. i am trying to build an app that generates a new number to reports created by our inspectors (our company is an inspection company). each inspector chooses the type of reports, the inspection date and the client and the app saves the data and creates a report number . the report number is generated depending on the type of the report and the date. for example if i have 3 reports of type "visual inspection" done in 2022, the new "visual inspection" report will have the number 4/2022.
here is the code I used to attempt this but unfortunately it is not working:
Views.py
from modulefinder import ReplacePackage
from django.shortcuts import render
from report.models import Report
from django.http import HttpResponse
from django.db.models.aggregates import Count
from django.db import transaction
from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from .serializers import ReportSerializer
#api_view(['GET','POST'])
def Report_add_view(request):
if request.method =='GET':
queryset = Report.objects.select_related('type').all()
serializer = ReportSerializer(queryset,many=True)
return Response(serializer.data,status=status.HTTP_200_OK)
elif request.method =='POST':
serializer = ReportSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data,status=status.HTTP_201_CREATED)
# Create your views here.
models.py
from django.db import models
# Create your models here.
class Client(models.Model):
name = models.CharField(max_length = 255)
code = models.PositiveIntegerField()
class ReportType(models.Model):
report_type = models.CharField(max_length = 255)
report_code = models.CharField(max_length = 255)
report_rev = models.CharField(max_length = 20)
def __str__(self):
return self.report_type
class Inspector(models.Model):
first_name = models.CharField(max_length = 255)
last_name = models.CharField(max_length = 255)
full_name = models.CharField(max_length = 255)
class Report (models.Model):
number = models.CharField(max_length=100)
type = models.CharField(max_length = 255)
inspection_date = models.DateField()
date_created = models.DateTimeField(auto_now_add=True)
inspector = models.ForeignKey(Inspector,on_delete=models.PROTECT)
client = models.ForeignKey(Client,on_delete=models.PROTECT)
type = models.ForeignKey(ReportType,on_delete=models.PROTECT)
reportlink = models.TextField()
serializers.py
from rest_framework import serializers
from .models import *
from django.db.models.aggregates import Count
from django.db.models import F
class ReportSerializer(serializers.ModelSerializer):
class Meta:
fields = ['number','type','inspection_date','inspector','client','reportlink','date_created']
model = Report
number = serializers.SerializerMethodField(method_name='report_number')
def report_number(self, report:Report):
print(report.type_id)
num1 = Report.objects.filter(type_id = report.type_id).all().aggregate(num=Count('id'))['num']+1
year = str(report.inspection_date)[:4]
print(year)
print(num1)
return str(num1) + "/"+ year
class InspectorSerializer(serializers.ModelSerializer):
class Meta:
fields = ['first_name','last_name','full_name']
model = Inspector
class ReportTypeSerializer(serializers.ModelSerializer):
class Meta:
fields = ['report_type','report_code','report_rev']
model = Report
screenshot of api result:
database screenshot:
As stated in the DRF doc: https://www.django-rest-framework.org/api-guide/fields/#serializermethodfield
SerializerMethodField is a read_only field.
To achieve what you're trying to do, i would override the "create" method of the serializer. It takes a dict of validated_data as parameter (generate thanks to the is_valid call you're doing).
In this method, you should be able to set validated_data["number"] with your desired value (return the modified dict at the end of the "create" method).
I'm not sure, but i think you should remove "number" from your list of fields in the serializer since you're calculating it.
I am trying to make quiz making application, since am new to django am unable to build the logic for saving foreign key field in database table. Someone please help me for the same.
models.py
In models.py , class quiztitle is for title of the quiz and id(foreign key,User model) of user who created that quiz.
class question is for question along with 4 options and the correct answer. Quizid(foreign key,quiztitle model) and id(foreign key,User model)
class answer is for the answer submitted by user who take the quiz.
from django.db import models
from django.contrib.auth.models import User
class quiztitle(models.Model):
Quiz_id = models.AutoField(primary_key=True)
Quiz_title = models.CharField(max_length=600)
id= models.ForeignKey(User, on_delete=models.CASCADE)
class question(models.Model):
Qid = models.AutoField(primary_key=True)
id = models.ForeignKey(User,on_delete=models.CASCADE)
Quiz_id = models.ForeignKey(quiztitle,on_delete=models.CASCADE)
Qques = models.TextField()
Qoption1 = models.TextField()
Qoption2 = models.TextField()
Qoption3 = models.TextField()
Qoption4 = models.TextField()
QAnswer = models.TextField()
class answer(models.Model):
Ansid = models.AutoField(primary_key=True)
Qid = models.ForeignKey(question,on_delete=models.CASCADE)
Quiz_id = models.ForeignKey(quiztitle, on_delete=models.CASCADE)
id = models.ForeignKey(User, on_delete=models.CASCADE)
Answer = models.TextField()
forms.py
from django.forms import ModelForm
from django.contrib.auth.forms import UserCreationForm
from django import forms
from django.contrib.auth.models import User
class CreateUserForm(UserCreationForm):
class Meta:
model = User
fields = ['username','email','password1','password2']
views.py
from django.shortcuts import render,redirect,HttpResponseRedirect
from .models import question ,quiztitle
from django.contrib import messages
from django.contrib.auth import authenticate,login,logout
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse
from django.contrib.auth.models import User
from django.forms import inlineformset_factory
from django.contrib.auth.forms import UserCreationForm
from .forms import CreateUserForm
from django.contrib import messages
from django.contrib.auth import authenticate,login,logout
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import Group
# Create your views here.
#login_required(login_url='home')
def handle_quiz(request):
if request.method=="POST":
# get post parameters
id = request.POST.get('id')
Quiz_title = request.POST.get('Quiz_title')
Quiz_id = request.POST.get('Quiz_id')
Qid = request.POST.get('Qid')
Qques = request.POST.get('Qques')
Qoption1 = request.POST.get('Qoption1')
Qoption2 = request.POST.get('Qoption2')
Qoption3 = request.POST.get('Qoption3')
Qoption4 = request.POST.get('Qoption4')
QAnswer = request.POST.get('QAnswer')
#I guess here is the mistake in saving the data in the mysql database
title = quiztitle(Quiz_title=Quiz_title,Quiz_id=Quiz_id,id=id)
title.save()
detail = question(Qid=Qid,Quiz_id=Quiz_id,id=id,Qques=Qques,Qoption1=Qoption1,Qoption2=Qoption2,Qoption3=Qoption3,Qoption4=Qoption4,QAnswer=QAnswer)
detail.save()
messages.success(request,"Your question has been added succesfully ")
return HttpResponseRedirect('/quizmaker')
return render(request,"createquiz.html")
def logoutUser(request):
logout(request)
return redirect('home')#redirect to login page
def home_page(request):
return render(request,'Home.html')
def registerPage(request):
if request.user.is_authenticated:
return redirect('home')
else:
form = CreateUserForm()
if request.method == 'POST':
form = CreateUserForm(request.POST)
if form.is_valid():
user = form.save()
username = form.cleaned_data.get('username')
messages.success(request, 'account has been created successfully for username' + username)
return redirect('login')
context = {'form':form}
return render(request,'register.html',context)
def handle_login(request):
if request.user.is_authenticated:
return redirect('home')
else:
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
return redirect('quizmaker')
else:
messages.info(request, 'Incorrect Username or Password')
context = {}
return render(request, 'login.html', context)
#login_required(login_url='login')
def handle_response(request):
data= question.objects.all()
return render(request, "student.html", {"messages": data})
admin.py
from django.contrib import admin
from .models import *
# Register your models here.
class quizadmin(admin.ModelAdmin):
list_display = ['Qid','Quiz_id','Qques','Qoption1','Qoption2','Qoption3','Qoption4','QAnswer']
admin.site.register(question,quizadmin)
admin.site.register(quiztitle)
As you guess your issue lies at title and detail.
To set a value to the ForeignKey you need an object. You can use instead an field with _id at the end.
Behind the scenes, Django appends "_id" to the field name to
create its database column name, see Django ForeignKey
It must be:
title = quiztitle.objects.create(
Quiz_title=Quiz_title,
Quiz_id=Quiz_id,
User_id_id=id # here
)
detail = question.objects.create(
Quiz_id_id=Quiz_id, User_id_id=id # and here,
Qid=Qid, Qques=Qques, Qoption1=Qoption1,
Qoption2=Qoption2, Qoption3=Qoption3,
Qoption4=Qoption4, QAnswer=QAnswer
)
I suggest you to use Django ModelForm here.
Based on the above, I recommend you also to rename your ForeignKey fields:
id > to user
Quiz_id > to quiztitle
Model style (Django Docs):
Use InitialCaps for class names (or for factory functions that return
classes).
Field names should be all lowercase, using underscores instead of
camelCase.
I've got a project where the user can create a model Parceiros and in that model is a model linking all the Servicos to that model Parceiros. The problem is that the Parceiros should be linked to the current user as the only way to create a Parceiros object is logging in before. After that the only user that should be able to change the Parceiros fields or Servicos should be the current user that created o Parceiros object.
I've read some questions and tried with context processors, but didn't manage to get the Parceiros linked to the user.
services/models.py
from django.db import models
from phone_field import PhoneField
from datetime import datetime
from django.contrib.auth import get_user_model
from django.template.defaultfilters import slugify
User = get_user_model()
class Parceiros (models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
nome = models.CharField(max_length=200)
endereco = models.TextField(max_length=400, blank=True)
responsavel = models.CharField(max_length=100)
tel = PhoneField(max_length=12)
created_at = models.DateTimeField(auto_now=True)
updated_at = models.DateTimeField(auto_now_add=True, blank=True)
ativo = models.BooleanField(default=False)
class Servicos (models.Model):
tipo = models.CharField(max_length=200)
objetivo = models.TextField(max_length=500, blank=True)
parceiro = models.ForeignKey(Parceiros, on_delete=models.CASCADE)
preco = models.DecimalField(max_digits=9, decimal_places=2, blank=True)
telefone = PhoneField(max_length=12, default='21968151502')
def get_image_filename(instance, filename):
tipo = instance.services.tipo
slug = slugify(tipo)
return "servicos_imagens/%s-%s" % (slug, filename)
class Imagens (models.Model):
servicos = models.ForeignKey(Servicos, on_delete=models.CASCADE)
imagem = models.ImageField(upload_to=get_image_filename)
services/views.py
from django.shortcuts import render, redirect
from .models import Servicos, Parceiros, Imagens
from django.views.generic import UpdateView, DetailView, ListView
from .forms import ParceirosForm, ServicosForm, ImagensForm
from django.contrib.auth.decorators import login_required
from django.contrib.auth.context_processors import auth
def home_view(request):
serv = Servicos.objects.all()
context = {'serv': serv }
return render (request, 'home.html', context)
#login_required
def parceiros_create(request):
if request.method =='POST':
form = ParceirosForm(request.POST)
Parceiros.user = auth.user
if form.is_valid():
parceiro = form.save(commit=False)
parceiro.save()
return redirect('home2')
else:
form = ParceirosForm()
context = {
'form': form,
}
return render (request, 'parceiroform.html', context)
def parceirosview(request):
user = Servicos.parceiro
serv = Servicos.objects.get(parceiro=user)
context = {'serv': serv}
return render(request, 'parceiro.html', context)
class ServicoView(DetailView):
model = Servicos
class ServicoUpdate(UpdateView):
model = Servicos
template_name = 'servicoform.html'
services/forms.py:
from django import forms
from .models import Servicos, Imagens, Parceiros
from phone_field import PhoneField
class ParceirosForm(forms.ModelForm):
class Meta:
prefix = 'parceiro'
model = Parceiros
fields = ['nome', 'endereco', 'responsavel', 'tel']
class ServicosForm(forms.ModelForm):
tipo = forms.CharField(max_length=200)
objetivo = forms.CharField(max_length=500)
preco = forms.DecimalField(max_digits=9, decimal_places=2)
telefone = PhoneField(max_length=12)
class Meta:
prefix = 'service'
model = Servicos
fields = ['tipo', 'objetivo', 'preco', 'telefone']
class ImagensForm(forms.ModelForm):
imagem = forms.ImageField(label='image')
class Meta:
model = Imagens
fields = ['imagem']
Parceiros is the class, so Parceiros.user = auth.user doesn't do anything.
When saving your form, you should assign the user to the actual instance of the model you're saving:
if form.is_valid():
parceiro = form.save(commit=False)
parceiro.user = request.user # assuming user is a FK field on Parceiros
parceiro.save()
Note that you should use request.user (not auth.user) which is the currently logged in user.
For the UpdateViews, you only need to change the queryset in order to ensure that only instances belonging to that user can be changed:
# inside class ServicoUpdate
# Servico is related to User via the Parceiros model
def get_queryset(self):
return super().get_queryset().filter(parceiro__user=self.request.user)
# inside class ParceiroUpdate
def get_queryset(self):
return super().get_queryset().filter(user=self.request.user)
And similarly for any other view that requires to restrict access to only the current logged in user's instances, if using a class-based view, override get_queryset().
I am trying to save an instance of a modelform in Django. I have setup a template to input information to the form and a view to handle the save. The form validates fine, but when trying to save it generates a foreigkey mismatch error. What am I doing wrong here?
I am running Django 2.0.0. I have already tried adding and removing the primary_key option without any luck and deleting my sqlite database, clearing all pycache, and migrating again. The problem persists.
#models.py
from django.db import models
import uuid
from users.models import Company, CustomUser
from delivery import settings
class Location(models.Model):
location_id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
address = models.CharField(max_length = 120)
date_added = models.DateField(auto_now_add = True)
class Shipment(models.Model):
date_created = models.DateField(auto_now_add=True)
sender_company = models.ForeignKey(Company, on_delete = models.PROTECT, related_name='sender')
receiver_company = models.ForeignKey(Company, on_delete = models.PROTECT, related_name='receiver')
origin = models.ForeignKey(Location, on_delete = models.SET_DEFAULT, default = 'Location no longer active.', related_name='origin')
destination = models.ForeignKey(Location, on_delete = models.SET_DEFAULT, default = 'DESTINATION UNKNOWN', related_name='destination')
expected_arrival = models.DateField()
weight = models.FloatField()
current_handler = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete = models.SET_DEFAULT, default = 'UNKNOWN')
shipment_id = models.UUIDField(unique=True, primary_key = True, default=uuid.uuid4, editable=False)
#forms.py
from django import forms
from .models import Location, Shipment
class LocationRegisterForm(forms.ModelForm):
class Meta:
model = Location
fields = '__all__'
class CreateShipment(forms.ModelForm):
class Meta:
model = Shipment
exclude = ['current_handler', 'shipment_id']
def clean_expected_arrival(self):
expected_arrival = self.cleaned_data['expected_arrival']
date_created = self.cleaned_data['date_created']
if expected_arrival < date_created:
raise ValidationError('Expected arrival date cannot be in the past.')
return expected_arrival
#views.py
from django.shortcuts import render, redirect
from .forms import CreateShipment, LocationRegisterForm
from users.permissions import group_required
#group_required('delivery_employee')
def new_shipment(request):
if request.method == 'POST':
form = CreateShipment(request.POST)
if form.is_valid():
temp_form = form.save(commit=False)
current_user = request.user
temp_form.current_handler = current_user
temp_form.save()
return redirect('dash-home')
else:
return render(request, 'shipments/new-shipment.html', {'form':form})
form = CreateShipment()
return render(request, 'shipments/new-shipment.html', {'form':form})
#group_required('delivery_employee')
def add_location(request):
if request.method == 'POST':
form = LocationRegisterForm(request.POST)
if form.is_valid():
form.save()
return redirect('new-shipment')
else:
return render(request, 'shipments/location-register.html', {'form':form})
form = LocationRegisterForm()
return render(request, 'shipments/location-register.html', {'form':form})
I get the error message:
File "C:\Python34\lib\site-packages\django\db\backends\sqlite3\base.py", line 303, in execute
return Database.Cursor.execute(self, query, params)
django.db.utils.OperationalError: foreign key mismatch - "shipments_shipment" referencing "shipments_location"
Thank you!
Your origin and destination fields set default value to plain strings, their default values should be the default Location instances instead.
Create methods like get_default_origin and get_default_destination where you will return the existing records from the database. Assign those methods to default argument, like
origin = models.ForeignKey(Location, on_delete = models.SET_DEFAULT, default=self.get_default_origin, related_name='origin')
destination = models.ForeignKey(Location, on_delete = models.SET_DEFAULT, default=self.get_default_destination, related_name='destination')
How to get user id from JWT token.
My JWT token has payload something like this:
{
"username": "Steve",
"is_admin": false,
"id": 1
}
How do I get access to user id?
I actually want to update certain fields in database as per the id, that are for a specific user.
Secondly after gaining the access how do I get update the fields?
models.py
class Profile(models.Model):
branch = models.CharField(max_length=20, null=True)
year = models.IntegerField(null=True)
image = models.ImageField(upload_to="accounts/images/", null=True, blank=True)
serializer.py
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = ('branch', 'year' ,'image',)
What will be the view to update these fields?
You should use the User object associated with the current request object. This assumes the cookie being present means that the user has a logged-in session when visiting the view in question,
def update_profile(request):
current_user = request.user
profile = Profile.objects.get(user=current_user.pk)
profile.update(field_a="value a", field_b="value b") # etc, example only
profile.save()
To make this possible, you also need to add the user relation as a OneToOne field within the Profile object:
from django.contrib.auth import User # assuming no customisation has been done to User model
# All your other imports and code
class Profile(models.Model):
branch = models.CharField(max_length=20, null=True)
year = models.IntegerField(null=True)
image = models.ImageField(upload_to="accounts/images/", null=True, blank=True)
user = models.OneToOneField(
User,
on_delete=models.CASCADE,
primary_key=False,
)
serializers.py
from django.contrib.auth import get_user_model
from rest_framework import serializers
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
exclude = ()
views.py
import base64
import json
from django.contrib.auth import get_user_model
from rest_framework.generics import RetrieveUpdateAPIView
class MyUserViewset(RetrieveUpdateAPIView):
queryset = get_user_model().objects.all()
serializer_class = MyUserSerializer
pagination_class = None
def get_object(self):
request = self.request
token = http_auth = request.META.get('HTTP_AUTHORIZATION', None)
token = token.replace("Token ", "")
user_json = json.loads(base64.b64decode(token.split(".")[1]))
user_id = user_json['id']
User = get_user_model()
user_obj = User.objects.get(id=user_id)
return user_obj