Currently i have the transfer model as followed:
class Transfers(models.Model):
class Meta:
db_table = "transfers"
verbose_name = 'Transfer'
verbose_name_plural = 'Transfers'
user = models.ForeignKey("backend.User", null=True, blank=True, related_name='user_transfer', on_delete=models.CASCADE)
to_account = models.ForeignKey("backend.User", null=True, blank=True, related_name='user_transfer_to_account', on_delete=models.SET_NULL)
A transfer object need to have from one user transfer to another user so i need to use the same User model
And in my admin.py:
class TransfersInline(admin.StackedInline):
model = Transfers
can_delete = False
extra = 0
max_num=0
form = TransfersAdminForm
class UserAdminCustom(admin.ModelAdmin):
exclude = ('password', 'last_login', 'is_superuser', 'is_staff', 'groups',
'user_permissions', 'username', 'first_name', 'last_name', 'is_active', 'date_joined')
inlines = [
TransfersInline,
]
def get_queryset(self, request):
qs = super(UserAdminCustom, self).get_queryset(request)
return qs.filter(is_staff=False)
def get_readonly_fields(self, request, obj=None):
return ('id', 'created', 'modified')
admin.site.register(User, UserAdminCustom)
In my admin i would like to display transfers inline that the User existed in user field of Transfers model but inline can't have multiple foreign key to the same model:
<class 'backend.admin.TransfersInline'>: (admin.E202) 'backend.Transfers' has more than one ForeignKey to 'backend.User'
My question is how do i only make TransfersInline use foreign key from user field instead of to_account field ? (transfer inline will have all the transfers object that the User is in user field )
Use fk_name='user' option for TransfersInline class.
You can check the docs
Related
Just an fyi, I'm pretty new to programming & Django in general. I've been teaching myself.
Before I get into the problem, I'll share my Django code:
models.py :
class User(AbstractUser):
# DATABASE FIELDS
email = models.EmailField(("email address"), unique=True)
REQUIRED_FIELDS = ['username']
USERNAME_FIELD = 'email'
# META
class Meta:
verbose_name = "User"
verbose_name_plural = "Users"
# TO STRING METHOD
def __str__(self):
return "User " + str(self.id) + " - " + self.email
class UserProfile(models.Model):
# RELATIONSHIP
user = models.ForeignKey(
to = User,
on_delete = models.CASCADE,
related_name = "user_account"
)
# DATABASE FIELDS
first_name = models.CharField(max_length=100, verbose_name="First Name")
last_name = models.CharField(max_length=100, verbose_name="Last Name")
date_created = models.DateField(auto_now=False, auto_now_add=False, verbose_name="Profile Created On")
role = models.CharField(max_length=255, verbose_name="User Demographic")
# META
class Meta:
verbose_name = "User Profile"
verbose_name_plural = "User Profiles"
# TO STRING METHOD
def __str__(self):
return self.first_name
forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import User
class AbstractUserCreationForm(UserCreationForm):
class Meta:
model = User
fields = ('username', 'email')
class AbstractUserChangeForm(UserChangeForm):
class Meta:
model = User
fields = UserChangeForm.Meta.fields
serializers.py
from rest_framework import serializers
from djoser.serializers import UserCreateSerializer, UserSerializer
from . import models
from .models import User, UserProfile
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = models.User
fields = ('id', 'email', 'username', 'password')
class UserCreateSerializer(UserCreateSerializer):
class Meta(UserCreateSerializer.Meta):
model = User
fields = ('id', 'email', 'username', 'password')
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields = ("id", "user", "first_name", "last_name", "date_created", "role")
The User(AbstractUser) model comes with some default fields. Two of those default fields I'm trying to reference are :
first_name & last_name
What I'm trying to do is, get those two default fields to connect with my UserProfile Model so that, when I create my User and fill out those fields, it will also show up in my UserProfile without having to fill it out there and connect it with a user.
Does anyone have any advice on how to achieve this connection/reference of two models?
(Just as an addition, I'm also using React for my frontend framework and have the requests working. It was just now that I realized I needed those two fields/models to connect after creating my SignUp component.)
By default, ForeignKey refers to the primary key for relation. But we can also point to other fields using to_field parameter.
I haven't tried the below code yet. But you can do something like this in your models.py:
models.py
class UserProfile(models.Model):
# RELATIONSHIP
user = models.ForeignKey(
to = User,
on_delete = models.CASCADE,
related_name = "user_account"
)
# DATABASE FIELDS
first_name = models.ForeignKey(User, to_field="firstname_field", verbose_name="First Name")
last_name = models.ForeignKey(User, to_field="lastname_field", verbose_name="Last Name")
You can refer the document here.
You need just to declare in Userprofile as OnetoOneField without declaring the first_name and last_name because User model has been declaring those field
models.py
from django.contrib.auth import get_user_model()
class UserProfile(models.model):
user = models.OnetoOneField(get_user_model(), on_delete=models.CASCADE)
I'm fairly new with the django restframework.
I am trying to create a serializer and a view for a model that has a foreignKey.
Models.py
class Job(models.Model):
"""A Job used to create a job posting"""
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
description = models.TextField()
job_type = models.CharField(max_length=12, choices=JOB_TYPE_CHOICES, default='Full-Time')
city = models.CharField(max_length=255)
state = models.CharField(max_length=255)
created_date = models.DateField(auto_now=False, auto_now_add=True)
salary = models.CharField(max_length=255)
position = models.CharField(max_length=255)
employer = models.CharField(max_length=255)
is_active = models.BooleanField(default=True)
def __str__(self):
return self.description[:50]
class Applicant(models.Model):
"""A applicant that can apply to a job"""
job = models.ForeignKey(Job, on_delete=models.CASCADE)
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
email = models.EmailField(max_length=254)
phone_number = PhoneNumberField()
resume = models.FileField(upload_to=resume_file_path, validators=[validate_file_extension])
def __str__(self):
return self.first_name
The idea is that Applicant will be able to apply to Job.
I can't seem to figure out how to get the Job id when a Applicant is applying to job.
serializers.py
class JobSerializer(serializers.ModelSerializer):
"""Serializer for tag objects"""
class Meta:
model = Job
fields = ('id', 'description', 'job_type', 'city', 'state', 'salary', 'position', 'employer', 'created_date', 'is_active')
read_only_fields = ('id',)
def create(self, validated_data):
"""Create a job posting with user and return it"""
return Job.objects.create(**validated_data)
class ApplyJobSerializer(serializers.ModelSerializer):
"""Serializer for applying to jobs"""
class Meta:
model = Applicant
fields = ('id', 'first_name', 'last_name', 'email', 'phone_number', 'resume')
read_only_fields = ('id',)
views.py
class ApplyJobView(generics.CreateAPIView):
"""Allows applicants to apply for jobs"""
serializer_class = serializers.ApplyJobSerializer
Below is an image of my http://localhost:8000/api/jobPosting/apply/ url
I don't know how i can bring in the Jobs as in option to my view so I can obtain the id field.
I get the following error when POST
null value in column "job_id" violates not-null constraint
You are not passing job field in serializer fields. Try this:
class ApplyJobSerializer(serializers.ModelSerializer):
"""Serializer for applying to jobs"""
class Meta:
model = Applicant
fields = ('id', 'first_name', 'last_name', 'email', 'phone_number', 'resume', 'job')
read_only_fields = ('id',)
I've overridden the UserAdmin class and wanted to add a user profile and some related objects as inline.
Userprofile works as expected, but for the ManyToMany relations I get now a table with related objects. That's not really ideal for my application, it's a bit cumbersome to change the related objects, and there's no need to add new objects this way.
I'd like to have a simple MultipleChoiceField containing the related objects. Is there an easy way to achieve this?
Here's my userprofile/admin.py:
from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin
from django.utils.translation import gettext_lazy as _
from django_admin_listfilter_dropdown.filters import RelatedOnlyDropdownFilter
from driverslog.models import Branch
from driverslog.models import Car
from .models import Userprofile
User = get_user_model()
class ProfileInline(admin.TabularInline):
model = Userprofile
can_delete = False
max_num = 0
extra = 0
fk_name = 'user'
class CarInline(admin.TabularInline):
model = Car.users.through
can_delete = True
verbose_name = _('Car')
verbose_name_plural = _('Cars')
extra = 0
class BranchInline(admin.TabularInline):
model = Branch.users.through
can_delete = True
verbose_name = _('Branch')
verbose_name_plural = _('Branches')
extra = 0
class CustomUserAdmin(UserAdmin):
inlines = (ProfileInline, BranchInline, CarInline)
list_display = ('username', 'first_name', 'last_name', 'is_staff', 'is_superuser', 'represents')
list_filter = ('is_active', 'is_staff', 'is_superuser', ('groups', RelatedOnlyDropdownFilter),
('branches', RelatedOnlyDropdownFilter), ('profile__represent', RelatedOnlyDropdownFilter),
('car', RelatedOnlyDropdownFilter))
def represents(self, obj):
return obj.profile.represent.count()
represents.short_description = _('Represents')
admin.site.unregister(User)
admin.site.register(User, CustomUserAdmin)
I solved it now without using inline fields.
What I did is overriding UserChangeForm and adding the fields for the reverse relation. It's working as expected and by now I didn't find any drawbacks (until now...).
admin.py:
class CustomUserAdmin(UserAdmin):
inlines = (ProfileInline,)
form = UserForm
...
fieldsets = (
(_('Personal info'), {'fields': ('username', 'first_name', 'last_name', 'email')}),
(_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions')}),
(_('Assignments'), {'fields': ('branches', 'cars')}),
)
forms.py:
class UserForm(UserChangeForm):
branches = forms.ModelMultipleChoiceField(queryset=Branch.objects.all())
cars = forms.ModelMultipleChoiceField(queryset=Car.objects.all())
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
instance = kwargs.get('instance')
if instance:
self.fields["branches"].initial = instance.branches.all().values_list('id', flat=True)
self.fields["cars"].initial = instance.cars.all().values_list('id', flat=True)
def save(self, commit=True):
if self.is_valid():
self.instance.cars.set(self.cleaned_data.get('cars'))
self.instance.branches.set(self.cleaned_data.get('branches'))
return super().save(commit)
models.py:
class Userprofile(models.Model):
class Meta:
verbose_name = _('Profile')
verbose_name_plural = _('Profiles')
user = models.OneToOneField(get_user_model(), on_delete=models.CASCADE, unique=True, related_name='profile', verbose_name=_('User'))
represent = models.ManyToManyField(get_user_model(), related_name='represent', blank=True, verbose_name=_('Represents'))
After 2017, filter_horizontal attribute added by django.
class CustomUserAdmin(UserAdmin):
filter_horizontal = ('branches', 'cars')
I have the following ListCreateAPIView
class TodoAPI(generics.ListCreateAPIView):
permission_classes = (IsAuthenticated, )
serializer_class = TodoSerializer
def get_queryset(self):
user = self.request.user
return Todo.objects.filter(user=user)
And in my serializers.py, I have
class TodoSerializer(serializers.ModelSerializer):
class Meta:
model = Todo
fields = ('id', 'title', 'description',
'completed', 'created_at')
read_only_fields = ('id', )
But the problem is when I POST data into the form, I get the following error:
IntegrityError at /todo/
NOT NULL constraint failed: todo_todo.user_id
models.py
class Todo(models.Model):
user = models.ForeignKey('auth.User', on_delete=models.CASCADE)
title = models.TextField(max_length=50)
description = models.TextField(max_length=200, blank=True, null=True)
completed = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
The problem is not with id field, but with user field. This field is not nullable in DB and since is required. You can just pass current user as defalt, for this use CurrentUserDefault:
class TodoSerializer(serializers.ModelSerializer):
user = serializers.HiddenField(default=serializers.CurrentUserDefault())
class Meta:
model = Todo
fields = ('id', 'title', 'description',
'completed', 'created_at', 'user')
I am trying to hide parts of my API (DRF) from the AbstractUser.
Here is my models.py:
class Company(models.Model):
name = models.TextField()
class User(AbstractUser):
company = models.ForeignKey(Company, null=True)
Here serializers.py:
class CompanySerializer(serializers.ModelSerializer):
class Meta:
model = Company
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = (
'username', 'email', 'company', 'first_name', 'last_name', 'date_joined', 'last_login', 'is_active',
'is_staff', 'groups', 'user_permissions'
)
And views.py:
class CompanyList(generics.ListCreateAPIView):
model = Company
serializer_class = CompanySerializer
class UserList(generics.ListCreateAPIView):
model = User
serializer_class = UserSerializer
So what I'm trying to get - get the JSON for the AbstractUser, but he can only see the company he is assigned to.
How can I do that? I have tried using def has_object_permission(), but I'm not really sure how to do it.
You can override the queryset to return user's company only.
class CompanyList(generics.ListCreateAPIView):
model = Company
serializer_class = CompanySerializer
def get_queryset(self):
return Company.objects.filter(pk=self.request.user.company.pk)