Django : Related Field got invalid lookup: user - python

I want to find practice data based on the user primary key.
So when I open the url: localhost:8080/api/practice-filter?user=1 it will output all practice data based on the user with id 1.
model.py
class Practice(models.Model):
practice_id = models.BigAutoField(primary_key=True)
user = models.ForeignKey('User', models.DO_NOTHING, default=None)
score = models.SmallIntegerField(null=True)
class Meta:
managed = True
db_table = 'practice'
def __str__(self):
return str(self.practice_id)
class User(models.Model):
user_id = models.BigAutoField(primary_key=True)
fullname = models.CharField(max_length=50)
email = models.CharField(max_length=100)
password = models.TextField()
class Meta:
managed = True
db_table = 'user'
def __str__(self):
return self.fullname
view.py
#api_view(['GET'])
def practice_filter(request):
if request.method == 'GET':
exercises = Practice.objects.all()
user = request.GET.get('user', None)
if user is not None:
practice_filtered = exercises.filter(user__user__icontains=user)
exercises_serializer = PracticeSerializer(practice_filtered, many=True)
return JsonResponse(exercises_serializer.data, safe=False)
But when i run the above code i get an error :
Related Field got invalid lookup: user
How to solve this error?
I do not know what to do.
I'm still a beginner and need a lot of guidance.
Please help.
Thank you.

You can go through foreign key fields with __.
but there is no field called user in User Model.
If you want to filter by user's fullname you can do this:
practice_filtered = exercises.filter(user__fullname__icontains=user)

Related

How to set up Django permissions for a custom user?

Good evening!
I have the following, a table containing my custom users (our dear Fellows) which will serve to login our users (by using the custom model).
◢ The custom backends with it's custom user model for the Fellows table.
from django.contrib.auth.hashers import check_password
from django.contrib.auth.models import User
from .models import CustomUser
class FellowBackend:
def authenticate(self, request, **kwargs):
'''Authenticates the user (custom model).'''
# Parameters
user_id = kwargs['username']
password = kwargs['password']
# Tentatives.
try:
user = CustomUser.objects.get(id = user_id)
# If the password matches.
if check_password(password, user.password):
return user
else:
# Triggers default login failed.
return None
except CustomUser.DoesNotExist:
return None
def get_user(self, user_id):
'''TODO: Test if this override is required.'''
try:
return CustomUser.objects.get(pk = user_id)
except CustomUser.DoesNotExist:
return None
◢ The custom user model.
class Faction(models.Model):
id = models.AutoField(db_column='ID', primary_key=True) # Field name made lowercase.
name = models.CharField(db_column='Name', max_length=64) # Field name made lowercase.
class Meta:
managed = False
db_table = 'Faction'
class CustomUser(AbstractBaseUser):
id = models.PositiveBigIntegerField(db_column='ID', primary_key=True) # ID.
display_name = models.CharField(db_column='Name', max_length=64, db_collation='utf8mb4_general_ci')
password = models.CharField(db_column='User_Password', max_length=256, blank=True, null=True)
gold = models.IntegerField(db_column='Gold') # Credits.
faction = models.ForeignKey('Faction', models.RESTRICT, db_column='Faction', default=1) # ID Faction.
last_login = models.DateTimeField(db_column='Last_Login', blank=True, null=True) # Last Login.
# Admin Panel Abstract Fields
active = models.BooleanField(default=True)
staff = models.BooleanField(default=False)
USERNAME_FIELD = 'id'
REQUIRED_FIELD = [] # id (username) and password required by default.
class Meta:
managed = False
db_table = 'Fellows'
def __str__(self):
return self.display_name # Test.
def has_perm(self, perm, obj=None):
"Does the user have a specific permission?"
# Simplest possible answer: Yes, always
return True
def has_module_perms(self, app_label):
"Does the user have permissions to view the app `app_label`?"
# Simplest possible answer: Yes, always
return True
#property
def is_staff(self):
"""Is the user a member of staff?"""
return self.staff
#property
def is_active(self):
"""Is the user active?"""
return self.active
So far so good, I can connect, do my stuff and even access the admin panel to manage every registered models if I am part of the staff.
However, let us say I want to add permissions between members of the staff, someone I hire for example to manage exclusively the Items table (from app Armory) while the other admin can have a total access to the models from any app.
◢ The armory app will contain the Item model (and it's references).
class Rarity(models.Model):
...
class ItemType(models.Model):
...
class Item(models.Model):
id = models.AutoField(db_column='ID', primary_key=True) # Identifier
name = models.CharField(db_column='Name', unique=True, max_length=64) # Name of the item.
description = models.TextField(db_column='Description', max_length=512, blank=True, null=True) # Description of the item.
source = models.CharField(db_column='Source', max_length=128, blank=True, null=True) # Source icon of the item.
rarity = models.ForeignKey('Rarity', models.CASCADE, db_column='Rarity') # ID of the rarity.
item_type = models.ForeignKey('ItemType', models.CASCADE, db_column='Item_Type') # ID of the item type.
item_value = models.PositiveIntegerField(db_column='Item_Value') # Value of the item.
sell = models.BooleanField(db_column='Sell') # If the item can be sold.
gift = models.BooleanField(db_column='Gift') # If the item can be sent.
dismantle = models.BooleanField(db_column='Dismantle') # If the item can be dismantled.
world = models.BooleanField(db_column='World') # If the item can be found in the world (using the bot's !wheel command).
class Meta:
db_table = 'n_rpg_items'
def __str__(self):
return self.name
◢ And an articles app that will contain the Article model.
from django.conf import settings
from django.db import models
class Article(models.Model):
id = models.AutoField(db_column='ID', primary_key=True) # ID
author = models.ForeignKey(settings.AUTH_USER_MODEL, db_column="ID_User", on_delete=models.CASCADE) # User ID
title = models.CharField(db_column='Title', max_length=32) # Title
content = models.TextField(db_column='Content') # Content
posted = models.DateTimeField(db_column='Posted') # Date Posted
source = models.CharField(db_column='Source', max_length=64, blank=True, null=True) # Source picture url of the article.
class Meta:
managed = False
db_table = 'Articles'
def __str__(self):
return 'Article : ' + self.title
To be more precise, when logging in the admin panel, admin_a will only be able to manage Items, while admin_b will be able to manage everything, Items and Articles.
The problem is, I searched for a while, the doc didn't helped me and I can't find anything that satisfies what I want to achieve so I am probably doing this wrong...
I was thinking about doing my own admin backends by adding a Role in the Fellows table but soon there will be no more use of framework if I start reinventing the wheel... :(
If anybody could share with me which solutions are conceivable, even a start, I would greatly appreciate!

How can I filter related field in django?

Say I have the model User which has a many-to-many relation with the model Company; and the model UserType, which is connected to both User and Company. Like this:
class User(models.Model):
name = models.TextField()
class Company(models.Model):
name = models.TextField()
users = models.ManyToManyField(User, related_name="companies")
class UserType(models.Model):
name = models.TextField()
company = models.ForeignKey(Company, related_name="user_types")
users = models.ManyToManyField(User, related_name="user_types")
I wanna find all Users in a Company, which is simple enough: User.objects.filter(companies=some_company). However, I also wanna filter the user_types field on the returned users objects, so that only UserType objects connected to the given Company is returned. To explain it with code, this should return true:
def check_user_types(users, company):
for user in users:
for user_type in user.user_types:
if user_type.company != company:
return false
return true
How would I do this?
I figured it out. For anyone facing the same problem, this solved it:
from django.db.models import Prefetch
users = User.objects.filter(companies=company).prefetch_related(
Prefetch(
"user_types",
queryset=UserType.objects.filter(company=company),
)
)

Django is overwriting the existing model

I have an abstract model class userabstract which has fields id(primary key), name(char field) and email(email field).
I am inheriting this class in two classes user, usertemp. After signing up, i want the data to be stored in usertemp. When user clicks on confirmation mail then that data will be transferred to user class.
But whats happening is, whenever someone signs up, usertemp model is updated instead of creating a new one. Same thing is happening with user class
Here is the code for models and views
class UserAbstract(models.Model):
id = models.AutoField(db_column='ID', primary_key=True, default=1) # Field name made lowercase.
name = models.CharField(db_column='NAME', max_length=100, default='') # Field name made lowercase.
email = models.CharField(db_column='EMAIL', max_length=100, default='') # Field name made lowercase.
def __str__(self):
return self.name
class Meta:
abstract = True
#python_2_unicode_compatible
class User(UserAbstract):
def __str__(self):
return self.name ;
class Meta:
managed = True
db_table = 'User'
#python_2_unicode_compatible
class Validation(models.Model):
key = models.AutoField(primary_key=True)
key_data = models.CharField(max_length=100, default='')
create_time = models.DateTimeField()
expire_time = models.DateTimeField()
def __str__(self):
return self.key_data
#python_2_unicode_compatible
class UserTemp(UserAbstract):
validation_key = models.ForeignKey(Validation, models.DO_NOTHING, related_name='+', default='') # Field name made lowercase.
verified = models.BooleanField(default=False)
def __str__(self):
return self.validation_key.key_data
views.py
def signup(request):
if request.method == 'POST':
form = FormTemp(request.POST, request.FILES)
if form.is_valid():
primary = form.cleaned_data['email']
try:
qdict = {}
qdict['email'] = primary
user = UserTemp.objects.get(**qdict)
if user.verified==True:
return HttpResponse("Account already exists")
except:
pass
email = form.cleaned_data['email']
signer = hashlib.sha256()
signer.update(primary)
validation_key = signer.hexdigest()
confirm_key = request.build_absolute_uri('/signup-confirm/')+'?key='+validation_key
send_mail('Confirm Your Mail', confirm_key, settings.EMAIL_HOST_USER, [email,])
valid = Validation(key_data=validation_key, create_time=datetime.now(), expire_time=datetime.now()+timedelta(days=30))
valid.save()
argsdict = {}
argsdict['name'] = form.cleaned_data['name']
argsdict['email'] = form.cleaned_data['email']
argsdict['validation_key'] = valid
argsdict['verified'] = False
usertemp = UserTemp(**argsdict)
usertemp.save()
return HttpResponse("Confirmation mail sent")
else:
return HttpResponse('Invalid Data')
else:
return HttpResponse('What are you doing here ? Tresspass')
The valid.save() is working fine and every time validation key is being saved but the usertemp contains only one model and that is the most recent one.
When i tried force_insert=True then its telling me that duplicate entry exist with same primary key. As you can see, the primary key field id is AutoField then why django not creating a new model when i am writing usertemp = UserTemp(**argsdict)
The problem here is that you've given your AutoField a default value. You're telling Django to assign that field the value 1 if you don't provide it, which means that you keep writing rows with the same id.
So just get rid of that default.
The broader point to understand is that defaults are a Django-level feature, while AutoField is a database-level feature. From the perspective of the database, there's no difference between explicitly assigned column values and Django default column values.

How can I save data in my custom field. (Extends from User) Django

I am using django authentication system. I have my User model
class User(models.Model):
first_name = models.CharField(max_length = 50)
last_name = models.CharField(max_length = 50)
username = models.CharField(max_length = 50, unique = True)
password = models.CharField(max_length = 50)
def __str__(self):
return "%s %s" %(self.first_name, self.last_name)
class Meta:
abstract = True
and recently I discovered that you cannot add some extra fields when you're using the django auth (for example: contact field). Google say, you can extend it. So, I extend it by making a UserProfile:
class UserProfile(User):
contact = models.CharField(max_length=20, null=True)
def __str__(self):
return self.contact_info
The problem is, I don't know how to add/save the data (contact) to the UserProfile. And how to display it in my template. I tried some but if failed:
views.py
if request.method == 'POST':
fname = request.POST['fname']
lname = request.POST['lname']
contact = request.POST['contact']
username = request.POST['username']
password = request.POST['password']
user = User.objects.create_user(username, email=None, password=password)
user.first_name = fname
user.last_name = lname
user.contact = contact
user.save()
user.contact = contact
user.save()
return redirect('system.views.user_login')
Is there any other way to save it?
I don't know where you saw that you can't add extra fields to your User model. You are already defining your own model; there is absolutely nothing to stop you from adding whatever fields you like.
However, if you are doing that, you must inherit from AbstractBaseUser, and set the AUTH_USER_MODEL setting to point to your model. Also, it makes no sense at all for you to define your User model as abstract.
To extend django auth user model, you can use AbstractUser.
from django.contrib.auth.models import AbstractUser
class UserProfile(AbstractUser):
contact = models.CharField(max_length=20, null=True)
def __str__(self):
return self.contact_info

Django REST - Custom Serializer for Full Username

I have an application with Django/Django-REST on the backend with Angular on the front-end. I am looking for the correct way to convert a user ID to a full username for display in an Angular JS modal.
Here is my serializer:
from rest_framework import serializers
from .models import ArtnetTasks
from django.contrib.auth.models import User
class TaskSerializer(serializers.ModelSerializer):
date_assigned = serializers.DateTimeField(format='%Y-%m-%d')
assigned_by_name = serializers.SerializerMethodField('full_username')
assigned_to_name = serializers.SerializerMethodField('full_username')
def full_username(self, id):
user = User.objects.get(id=id)
name = user.first_name + " " + user.last_name
return name
class Meta:
model = ArtnetTasks, Users
fields = ('id', 'headline', 'message', 'assigned_to', 'assigned_to_name', 'assigned_by', 'assigned_by_name', 'date_assigned', )
My Model:
class ArtnetTasks(models.Model):
id = models.IntegerField(primary_key=True)
headline = models.CharField(max_length=75L)
message = models.TextField()
response_message = models.TextField(blank=True)
assigned_to = models.IntegerField(null=True, blank=True)
assigned_by = models.IntegerField(null=True, blank=True)
date_assigned = models.DateTimeField()
date_completed = models.DateTimeField(null=True, blank=True)
is_active = models.IntegerField(null=True, blank=True)
date_updated = models.DateTimeField(null=True, blank=True)
class Meta:
db_table = 'artnet_tasks'
assigned_to and assigned_by are user_id's that correspond with auth_user
It is throwing the following error then promptly breaking the Angular AJAX calls, the error from what I can tell is "argument must be a string or a number\054 not 'dict'"
This is my first project using both Django-REST and Angular and am sure I am missing something obvious.
Thanks in advance!
So, you can not set more than one model on your serializer. Your serializer can only handle one model per time. Another thing, the SerializerMethodField has as parameter self and obj, where, obj is your ArtnetTasks instance. As a better RESTful practice, I recommend you the follow example, if your user is authenticated:
class TaskSerializer(serializers.ModelSerializer):
date_assigned = serializers.DateTimeField(format='%Y-%m-%d')
assigned_by_name = serializers.SerializerMethodField('get_user_full_name')
assigned_to_name = serializers.SerializerMethodField('get_user_full_name')
def get_user_full_name(self, obj):
request = self.context['request']
user = request.user
name = user.first_name + " " + user.last_name
return name
class Meta:
model = ArtnetTasks
fields = ('id', 'headline', 'message', 'assigned_to', 'assigned_to_name', 'assigned_by', 'assigned_by_name', 'date_assigned', )
Better than this, I recommend you to create a simple serializer to the User model, and then , instead to use assigned_by_name and assigned_to_name, you can use:
user = YourUserSerialuzer()
But you will need a relation between User and ArtnetTasks model to do that.
You can see more examples of how do this, here: http://www.django-rest-framework.org/api-guide/relations

Categories