I'm trying to implement a simple pgtrigger.Protect on a table that will do a boolean value check to a foreign key's column. I have written the trigger correctly but when the migration happens, the foreign key's column is not properly referenced. Need help.
User Table
from datetime import datetime as DateTime
from django.db.models import (
BooleanField, CASCADE, CharField, DateField, DateTimeField, EmailField,
ForeignKey, IntegerField, JSONField, Model, OneToOneField
)
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
import pgtrigger
from app.models.user.util.manager import UserAccountManager
class User(AbstractBaseUser, PermissionsMixin):
class Meta:
db_table = "user"
managed = True
triggers = [
pgtrigger.SoftDelete(name = "User_SOFTDELETE", field = "is_active", value = False)
]
id = CharField(
max_length = 10,
primary_key = True,
null = False,
blank = False,
unique = True
)
account_name = CharField(max_length=50, null=False, blank=False, unique=True)
dob = DateField(auto_now=False, auto_now_add=False, null=False, blank=False)
email = EmailField(max_length=50, null=False, blank=False, unique=True)
password = CharField(max_length=254, null=False, blank=False)
content_provider = BooleanField(default=False, null=False, blank=False)
is_staff = BooleanField(default=False, null=False, blank=False)
is_active = BooleanField(default=False, null=False, blank=False)
USERNAME_FIELD = "id"
REQUIRED_FIELDS = ["account_name", "dob", "email", "password"]
objects = UserAccountManager()
def __str__(self):
return self.account_name
class Product(Model):
class Meta:
db_table = "product"
triggers = [
pgtrigger.SoftDelete(name = "Product_SOFTDELETE", field = "is_active", value = False),
pgtrigger.Protect(
name = "Product_PROTECT_insert",
operation = pgtrigger.Insert | pgtrigger.Update,
when = pgtrigger.Before,
condition = pgtrigger.Q(new__id_provider__content_provider = True)
)
]
id = CharField(
max_length = 20,
primary_key = True,
null = False,
blank = False,
unique = True
)
id_provider = ForeignKey(User, db_column="id_provider", on_delete=CASCADE)
.....
.....
.....
Migration Error:
LINE 45: FOR EACH ROW WHEN (NEW."content_provider")
In the migration file, it needs to be converted to something like NEW."user"."content_provider". How can I create this trigger properly to a foreign key's column? Need Help
Related
Well I'm trying to create user addition form from frontend that creates user and additional info based on custom user model.But I'm getting duplicate key value violates unique constraint "users_driver_email_key" DETAIL: Key (email)=() already exists.
here is my code:
Models.py
class CustomUser(AbstractUser):
is_driver = models.BooleanField(default=False)
is_accountant = models.BooleanField(default=False)
is_dispatcher = models.BooleanField(default=False)
class Driver(models.Model):
driver_user = models.OneToOneField(CustomUser, on_delete = models.CASCADE, primary_key = True)
full_name = models.CharField(max_length=50, default=None)
phone_number = models.CharField(max_length=50, default=None)
email = models.EmailField(unique=True,max_length=255, default=None)
address = models.CharField(max_length=70, default=None)
country = models.CharField(max_length=50, default=None)
state = models.CharField(choices=US_STATES,max_length=50, default=None)
city = models.CharField(max_length=50, default=None)
zipp = models.CharField(max_length=50, default=None)
birth_date = models.DateField(default=None)
license_no = models.IntegerField(default=None)
license_exp_date = models.DateField(default=None)
last_medical = models.DateField(default='', blank=True, null=True)
next_medical = models.DateField(default='', blank=True, null=True)
last_drug_test = models.DateField(default='', blank=True, null=True)
next_drug_test = models.DateField(default='', blank=True, null=True)
date_created = models.DateTimeField(auto_now_add=True)
date_edited = models.DateTimeField(auto_now=True)
status = models.IntegerField(choices=STATUS, default=1)
class DriversFiles(models.Model):
file = models.FileField(upload_to="media/", blank=True, null=True)
driver_files = models.ForeignKey('Driver', on_delete=models.CASCADE, default=None, null=True)
#receiver(post_save, sender=CustomUser)
def create_user_profile(sender, instance, created, **kwargs):
# if Created is true (Means Data Inserted)
if created:
# Check the user_type and insert the data in respective tables
if instance.is_driver:
Driver.objects.create(
driver_user=instance,
full_name = "123",
phone_number = "123",
email = "",
address = "123",
country = "123",
state = "123",
city = "123",
zipp = "213",
birth_date = '2022-01-01',
license_no = '1234',
license_exp_date = '2022-01-01',
last_medical= '2022-01-01',
next_medical = '2022-01-01',
last_drug_test = '2022-01-01',
next_drug_test = '2022-01-01',
)
Views.py
def create_driver_view(request):
if request.method == "POST":
add_driver = DriverForm(request.POST)
add_driver_file = request.FILES.getlist("file")
if add_driver.is_valid():
#For Custom User
password = 'Ga20224$5%'
full_name = add_driver.cleaned_data['full_name']
email = add_driver.cleaned_data['email']
phone_number = add_driver.cleaned_data['phone_number']
address = add_driver.cleaned_data['address']
country = add_driver.cleaned_data['country']
state = add_driver.cleaned_data['state']
city = add_driver.cleaned_data['city']
zipp = add_driver.cleaned_data['zipp']
birth_date = add_driver.cleaned_data['birth_date']
license_no = add_driver.cleaned_data['license_no']
license_exp_date = add_driver.cleaned_data['license_exp_date']
last_medical = add_driver.cleaned_data['last_medical']
next_medical = add_driver.cleaned_data['next_medical']
last_drug_test = add_driver.cleaned_data['last_drug_test']
next_drug_test = add_driver.cleaned_data['next_drug_test']
print(email)
username = email.split('#')[0] + uuid.uuid4().hex[:2]
user = CustomUser.objects.create_user(
username = username,
password = password,
is_driver = True,
email = email
)
#For Driver Profile
user.driver.full_name = full_name
user.driver.email = email
user.save()
# for i in add_driver_file:
# DriversFiles.objects.create(driver_files=user, file=i)
return redirect('drivers:list_driver')
else:
print(add_driver.errors)
else:
add_driver = DriverForm()
add_driver_files = DriverFormUpload()
return render(request, "drivers/add.html", {"add_driver": add_driver, "add_driver_files": add_driver_files})
I was getting eror {{message}} that username or email is already taken but now it opens debugger. In addition it creates user account with the same emails but then dont creates Driver table cause email is not unique.
I'm new in django and Just wanted to create custom user models, but there is so many headaches. What should I do here. or how can I create custom user models correctly
As you are inheriting from AbstractUser class (see line 334), you already have an email field on your user instance. Thus, removing the email field from the driver model should fix your issue.
class AbstractUser(AbstractBaseUser, PermissionsMixin):
"""
An abstract base class implementing a fully featured User model with
admin-compliant permissions.
Username and password are required. Other fields are optional.
"""
username_validator = UnicodeUsernameValidator()
username = models.CharField(
_("username"),
max_length=150,
unique=True,
help_text=_(
"Required. 150 characters or fewer. Letters, digits and #/./+/-/_ only."
),
validators=[username_validator],
error_messages={
"unique": _("A user with that username already exists."),
},
)
first_name = models.CharField(_("first name"), max_length=150, blank=True)
last_name = models.CharField(_("last name"), max_length=150, blank=True)
email = models.EmailField(_("email address"), blank=True)
If you want to use the email field as auth and unique, you could approach it like so:
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.utils.translation import ugettext_lazy as _
from .managers import CustomUserManager
class CustomUser(AbstractUser):
username = None
email = models.EmailField(_('email address'), unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = CustomUserManager()
def __str__(self):
return self.email
Django provided to facilities to customize the Default USER Model.
Have Two Famous approaches...
1 - Extending User Model Using a Custom Model Extending AbstractUser
from django.db import models
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
bio = models.TextField(max_length=500, blank=True)
location = models.CharField(max_length=30, blank=True)
birth_date = models.DateField(null=True, blank=True)
profile_pic = models.ImageField(upload_to ='/Propife/',null=True, blank=True)
2 - Extending User Model Using a Custom Model Extending AbstractBaseUser
from django.db import models
from django.core.mail import send_mail
from django.contrib.auth.models import PermissionsMixin
from django.contrib.auth.base_user import AbstractBaseUser
from django.utils.translation import ugettext_lazy as _
from .managers import UserManager
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('email address'), unique=True)
first_name = models.CharField(_('first name'), max_length=30, blank=True)
last_name = models.CharField(_('last name'), max_length=30, blank=True)
date_joined = models.DateTimeField(_('date joined'), auto_now_add=True)
is_active = models.BooleanField(_('active'), default=True)
profile_pic = models.ImageField(upload_to ='/Propife/',null=True, blank=True)
bio = models.TextField(max_length=500, blank=True)
location = models.CharField(max_length=30, blank=True)
birth_date = models.DateField(null=True, blank=True)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
NOTE:- put all fields with null=True blank=True which you want to use for profile purpose. and create a form with CustomUserModel and then write the Update functionality for profile fields which leave with null=True blank=True.
I have the following models in my Django project from different apps
Student App Model
from django.db import models
import batch.models
import course.models
class Student(models.Model):
ACTIVE = 'Active'
DROPPED = 'Dropped'
TRANSFERRED = 'Transferred'
INACTIVE = 'Inactive'
studentStatus = [
(ACTIVE, 'atv'),
(DROPPED, 'drp'),
(TRANSFERRED, 'trf'),
(INACTIVE, 'inv'),
]
first_name = models.CharField('First Name', max_length=30)
last_name = models.CharField('Last Name', max_length=30)
student_batch = models.ManyToManyField(batch.models.Batch,related_name='batch')
contact_no = models.CharField('Contact No', max_length=20, null=True, blank=True)
email_address = models.EmailField('Student Email', null=True, blank=True)
student_status = models.CharField('Student Status', max_length=20, choices=studentStatus,
default=ACTIVE)
student_remark = models.CharField('Student Remark', max_length=255, null=True, blank=True)
student_course = models.ManyToManyField(course.models.Course,related_name='course')
created_on = models.DateTimeField(auto_now_add=True)
updated_on = models.DateTimeField(auto_now=True)
def __str__(self):
return f"{self.first_name} {self.last_name}"
Batch App Model
from django.db import models
from datetime import date, timezone
import course.models
import trainer.models
from django.contrib.auth.models import User
class Batch(models.Model):
ACTIVE = 'Active'
HOLD = 'Hold'
SCHEDULED = 'Scheduled'
CANCELED = 'Canceled'
TRANSFERRED = 'Transferred'
batchStatus = [
(ACTIVE, 'act'),
(HOLD, 'hld'),
(SCHEDULED, 'scd'),
(CANCELED, 'cld'),
(TRANSFERRED, 'trd'),
]
batch_course = models.ForeignKey(course.models.Course, on_delete=models.SET_NULL, blank=True, null=True)
batch_trainer = models.ForeignKey(trainer.models.Trainer, on_delete=models.SET_NULL, blank=True, null=True)
batch_time = models.TimeField('Batch Time', blank=True, null=True)
batch_start_date = models.DateField('Batch Start Date', default=date.today)
created_by = models.ManyToManyRel('Batch Created By', to=User)
batch_status = models.CharField('Batch Status', choices=batchStatus, default=ACTIVE, max_length=20)
created_on=models.DateTimeField(auto_now_add=True)
updated_on=models.DateTimeField(auto_now=True)
def __str__(self):
return f"{self.batch_course} | {self.batch_time} | {self.batch_start_date}"
Course App Model
from django.db import models
from django.core import validators
class Course(models.Model):
name = models.CharField('Course Name', max_length=120)
duration = models.PositiveIntegerField('Course Duration')
created_on = models.DateTimeField(auto_now_add=True)
updated_on = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
want output in student view which shows
all students data with their associated course and batch
eg:
Student Name | Course Name | Batch Name
when i tried it with foreign key, i got all result with primary key of foreign table, i am not sure how to get name associated with those key as i don't have single result so i can compare it with foreign key.
student_detail = Student.objects.all().values("first_name", "student_course__name", "student_batch__batch_time").prefetch_related("student_batch", "student_course")
As in your Course model, I didn't find any name field, so I put batch_time instead of name for your understanding.
I have two models.
The first one represents different Projects with a name, an ID and a description
The second one is for tracking which user is in which Project.
So my models look like this:
from django.contrib.auth.models import User
# Create your models here.
class Project(models.Model):
id = models.AutoField(db_column = 'db_ID', primary_key = True)
name = models.CharField(max_length=500, default = None)
descriptor = models.CharField(max_length = 1000, null = True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'projects'
def __str__(self):
return self.name
class Userproject(models.Model):
id = models.AutoField(db_column = 'db_ID', primary_key = True)
user = models.ForeignKey(User, on_delete= models.SET_NULL, null = True)
project = models.ForeignKey('Project', on_delete = models.SET_NULL, null = True)
created_at = models.DateTimeField(auto_now_add=True, null=True)
updated_at = models.DateTimeField(auto_now=True, null = True)
class Meta:
db_table = 'UserProjects'
def __str__(self):
return self.id
In the Userproject there there is only the UserID and the ProjectID, both are ForeignKeys to the other models.
When I get a GET-Request with a username, I can get the userID , then I can filter all the Userprojects by the userID and serialize all those where the given user is present. But How would I include the Project data as well If I want to send the name of the Project as well?
So you can run a query with power operators to filter data based on foreign object values.
user_projects = Userproject.objects.filter(user_id=user_id, project__name='yourproject')
Now to access project data from user_project you can use . operator.
if user_projects.exists():
print(user_projects[0].user_id)
print(user_projects[0].project.name)
print(user_projects[0].project.descriptor)
To get values directly from the ORM, use .values().
user_projects = Userproject.objects.filter(user_id=user_id, project__name='yourproject').values('project__name', 'project__descriptor)
This will fetch only the columns you specify as parameters.
I am trying to delete the "profiles" manually using "admin" portal of the DJANGO, but when I click on delete after selecting some profiles, I am getting an error as -> 'NoneType' object has no attribute 'delete'
I am using signals in my code.
signals.py code:-
from .models import Profile
from django.contrib.auth.models import User
from django.db.models.signals import post_save, post_delete
def createProfile(sender, instance, created, **kwargs):
if created:
user = instance
profile = Profile.objects.create(
user = user,
username = user.username,
email = user.email,
name = user.first_name,
)
def updateUser(sender, instance, created, **kwargs):
profile = instance
user = profile.user
if created == False:
user.first_name = profile.name
user.username = profile.username
user.email = profile.email
user.save()
def deleteUser(sender, instance, **kwargs):
user = instance.user
user.delete()
post_save.connect(createProfile, sender = User)
post_save.connect(updateUser, sender = Profile)
post_delete.connect(deleteUser, sender = Profile)
models.py code:-
from django.db import models
from django.contrib.auth.models import User
import uuid
# Create your models here.
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True)
name = models.CharField(max_length=200, blank = True, null = True)
location = models.CharField(max_length=200, blank = True, null = True)
username = models.CharField(max_length=200, blank = True, null = True)
email = models.EmailField(max_length=500, blank=True, null = False)
short_intro = models.CharField(max_length=200, blank=True, null=True)
bio = models.TextField(blank=True, null=True)
profile_image = models.ImageField(null = True, blank = True, upload_to = 'profiles/', default = 'profiles/user-default.png')
social_github = models.CharField(max_length=200, blank = True, null = True)
social_twitter = models.CharField(max_length=200, blank = True, null = True)
social_linkedin = models.CharField(max_length=200, blank = True, null = True)
social_youtube = models.CharField(max_length=200, blank = True, null = True)
created = models.DateTimeField(auto_now_add=True)
id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False)
def __str__(self):
return str(self.username)
class Skill(models.Model):
owner = models.ForeignKey(Profile, on_delete=models.CASCADE, null = True, blank = True)
name = models.CharField(max_length=200, null=True, blank = True)
description = models.TextField(null = True, blank = True)
created = models.DateTimeField(auto_now_add=True)
id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False)
def __str__(self):
return str(self.name)
I don't know, why am I getting this error, can anyone figure it out?
You are deleting a Profile, but that Profile has no linked user, since the user is NULL/None.
You can make your signal safer with:
def deleteUser(sender, instance, **kwargs):
user = instance.user
if user:
user.delete()
I'm trying to import three datasets for three data models that are interconnected and I cannot seem to properly add in the foreign key. When I try to use the fields.Feild() function to create the foreign key, I get the nameerror in this line: hid = fields.Field(column_name='hid',attribute='hid',..). Please help, I've been trying to upload my datasets for a week. I originally tried to do it manually, but was unable, so now I'm using this package django-import-export.
NameError: name 'fields' is not defined
Here is my models.py
class Service(models.Model):
"""Model representing an author."""
serviceid = models.UUIDField(default=uuid.uuid4, help_text='Unique ID for this particular service in database')
desc_us = models.TextField(blank=True, primary_key = True)
cpt = models.IntegerField(default= 10000)
price = models.DecimalField(max_digits=6, decimal_places=2, blank=True, null=True)
_str__(self):
"""String for representing the Model object."""
return self.desc_us
# Create your models here.
class Library(models.Model):
"""Model representing Librarys."""
hid = models.CharField(max_length = 8, null=True)
name = models.CharField(max_length=200, primary_key=True)
hopid = models.UUIDField(default=uuid.uuid4, help_text='Unique ID for this particular library in database')
address = models.CharField(max_length = 200, null = True)
city = models.CharField(max_length = 50, null = True)
state = models.CharField(max_length = 2, null=True)
zipcode = models.CharField(max_length = 5, null=True)
phone = models.CharField(max_length = 12, null=True)
updateDate = models.DateField(blank=True, null=True)
class Meta:
ordering = ['hopid']
def __str__(self):
"""String for representing the Model object."""
return f'{self.name} ({self.address})'
class Price(models.Model):
"""Model with all the hospital prices by service."""
priceid = models.UUIDField(primary_key=True, default=uuid.uuid4, help_text='Unique ID for this particular service in database')
com_desc = models.CharField(max_length = 200, blank = True, null = True)
service = models.ForeignKey("Service", on_delete=models.SET_NULL, null=True)
price_offer = models.DecimalField(max_digits=8, decimal_places=2, blank=True)
comments = models.CharField(max_length = 200, blank = True, null =True)
hospital = models.ForeignKey("Hospital", on_delete=models.SET_NULL, null=True)
class Meta:
ordering =['service']
def __str__(self):
return f'{self.hospital.name} ({self.service.desc_us}) ({self.price_offer})'
Here is admin.py
from import_export.admin import ImportExportModelAdmin
from import_export import resources
class ServiceResource(resources.ModelResource):
class Meta:
model = Service
report_skipped = True
exclude = ('id','serviceid')
import_id_fields = ('desc_us', 'cpt', 'price',)
#admin.register(Service)
class ServiceAdmin(ImportExportModelAdmin):
resource_class = ServiceResource
class LibraryResource(resources.ModelResource):
class Meta:
model = Library
report_skipped = True
exclude = ('id','hopid','updateDate')
import_id_fields = ('hid', 'name', 'address', 'city', 'state', 'zipcode', 'phone',)
#admin.register(Library)
class LibraryAdmin(ImportExportModelAdmin):
resource_class = LibraryResource
class PriceResource(resources.ModelResource):
hid = fields.Field(column_name='hid',attribute='hid', widget=ForeignKeyWidget(Library, 'name'))
class Meta:
model = Price
report_skipped = True
exclude = ('id','priceid')
#admin.register(Price)
class PriceAdmin(ImportExportModelAdmin):
list_display = ('com_desc', 'cpt', 'price_offer', 'comments', 'hid',)
resource_class = PriceResource
At the top, add:
import import_export
Then change your line of code to:
hid = import_export.fields.Field(column_name='hid',attribute='hid', widget=ForeignKeyWidget(Library, 'name'))
You're currently not telling Django what library to look for 'fields' in, so it doesn't know.