Django ManytoMany field remains empty after .add() method called - python

I'm using django to create a signup platform where students can signup to weekly classes.
Each class is a django model called ClassCards which has a ManytoMany relation to User model called signed_up_student that represents all the users signed up for that class as seen below
class ClassCards(models.Model):
content = models.CharField(max_length=100, default = '')
date = models.DateField(blank=True, null = True)
time = models.TimeField(blank=True,null=True)
signed_up_students = models.ManyToManyField(User,blank=True)
full = models.BooleanField(default = False)
max_students = models.IntegerField(default=4)
teacher = models.CharField(max_length=100, default='Adi')
I would like to add a subscription option that will automatically sign up subscribed students to this weeks class. Here is my Subscription model:
class Subscriptions(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null =True)
day = models.CharField(max_length=100, choices=day_choices, null=True)
time = models.TimeField(blank=True, null=True)
num_of_times_used = models.IntegerField(default=0)
cap = models.IntegerField(default=52)
active = models.BooleanField(default= True)
expirey_date = models.DateField()
date_created = models.DateField(default = timezone.now)
To accomplish this I have created a post_save signal:
#receiver(post_save,sender=ClassCards)
def apply_subsciptions(sender,instance,created, **kwargs):
if created:
subs = Subscriptions.objects.filter(day=instance.date.strftime("%A"),
time=instance.time)
for s in subs:
instance.signed_up_students.add(s.user)
print(instance.signed_up_students.get())
The code runs properly when a ClassCards is saved without throwing any errors and the print statement prints the relevant User However when I look on the admin page, I see that there are no users in the signed_up_students field.
I Would like to understand why this isn't working as desired which should adding that user to the ManytoMany field and what is the best practice for automatically updated a ManytoMany fields.

a little modification to the class ClassCards
class ClassCards(models.Model):
signed_up_students = models.ManyToManyField(User, symmetrical=False, related_name="student_cards_students_has", blank=True)
def signed_students_list(self):
return self.signed_up_students.all()
def cards_asigned_to_student_list(self):
return self.student_cards_students_has.all()
def assign_student(self, user):
self.signed_up_students.add(user)
def unsign_user(self, user):
self.signed_up_students.remove(user)
now in the signals
#receiver(post_save,sender=ClassCards)
def apply_subsciptions(sender,instance,created, **kwargs):
if created:
subs = Subscriptions.objects.filter(day=instance.date.strftime("%A"),time=instance.time)
for s in subs:
instance.assign_student(s.user)
instance.save()
print(instance.signed_students_list())
print(instance.cards_asigned_to_student_list())

Related

Django-Extra-Views: Inlines child model gets author none. How do I set it the same as the parent?

I have been spinning my wheels on this issue for a day or two. I have django web application that has 3 models
users/models.py:
from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth.models import User
# Create your models here.
class ExtendedUser(models.Model):
user=models.OneToOneField(User,null=True, on_delete=models.CASCADE)
def full_name(self):
return (self.user.get_full_name())
def __str__(self):
return self.user.get_full_name()
#receiver(post_save, sender=User)
def create_or_update_user_extendeduser(sender, instance, created, **kwargs):
if created:
ExtendedUser.objects.create(user=instance)
instance.extendeduser.save()
playground/models.py:
class Customer(models.Model):
def __str__(self):
return self.Customer_Name
Customer_Name = models.CharField(max_length=100)
SFDC_Customer_Record_Number = models.IntegerField(default='')
Zone = models.CharField(max_length=50, default='')
Government = models.BooleanField(default=False)
date_posted = models.DateTimeField(default=timezone.now)
customerauthor = models.ForeignKey(ExtendedUser, on_delete=models.DO_NOTHING,default=ExtendedUser)
def get_absolute_url(self):
return reverse('playground-home')
class Vue_Quote(models.Model):
def __str__(self):
return self.Quote_Name
Quote_Name = models.CharField(max_length=100)
SFDC_Golden_Opp_ID = models.IntegerField()
Vue_System_Count = models.IntegerField()
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(ExtendedUser, on_delete=models.DO_NOTHING,default=ExtendedUser,blank=True,null=True)
Quote_Type = models.CharField(max_length=100)
Customer = models.ForeignKey(Customer, on_delete=models.DO_NOTHING, default='')
def get_absolute_url(self):
return reverse('quote-detail',kwargs={'pk': self.pk})
I am using the 3rd party application django-extra-views to create a single form which allows a user to create a customer and quote at the same time. Views.py:
class QuoteInline(InlineFormSetFactory):
model = Vue_Quote
fields = ['Quote_Name','SFDC_Golden_Opp_ID','Vue_System_Count','Quote_Type',]
factory_kwargs = {'extra':1}
class CreateQuoteInlinesView(CreateWithInlinesView):
model = Customer
inlines = [QuoteInline]
fields = ['Customer_Name','SFDC_Customer_Record_Number','Zone','Government']
template_name= 'quote_and_customer.html'
def forms_valid(self, form, inlines):
form.instance.customerauthor = ExtendedUser.objects.get(user=self.request.user)
return super().forms_valid(form,inlines)
All of this is working great except for that I am not able to save the author for the Vue_Quote model...I always get "None":
Image of Vue_Quote.author = None from my form
I have tried a wide range of solutions but cannot seem to solve this and I am finding very little documentation on django-extra-views to support my finding a solution.
Any assistance is greatly appreciated!
Welp, I've looked at the source code and tried to figure it out.. It's really abstract and a lot of inheritance
This would be my best guess:
def forms_valid(self, form, inlines):
user = ExtendedUser.objects.get(user=self.request.user)
form.instance.customerauthor = user
for i in inlines:
i.instance.author = user
i.save()
return super().forms_valid(form,inlines)
Or if you wanted to also define the Customer field in this forms_valid you could do it after the super call
You could try something like this:
def forms_valid(self, form, inlines):
user = ExtendedUser.objects.get(user=self.request.user)
form.instance.customerauthor = user
customerObj = super().forms_valid(form,inlines)
for i in inlines:
i.instance.author = user
i.instance.Customer = customerObj
i.save()
return customerObj

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!

Cross-Saving possible?

Is there's a "cross-saving"-possibility between to models inside my django-application?
For example:
models.py
class Person(models.Model):
first_name = models.CharField()
last_name = models.CharfFeld()
age = models.IntegerField()
value_person= models.IntegerField()
date_created = models.DateField
class Account():
name = models.CharField()
description = models.Textarea()
person = models.ForeignKey(Person, null=False, blank=False, on_delete=models.CASCADE)
value_a = models.IntegerField()
value_b = models.IntegerField()
date_created = models.DateField
forms.py:
class UpdateAccountForm(ModelForm):
class Meta:
model = Account
exclude = [
'name',
'date_created',
]
views.py:
[...]
account_db = Account.objects.get(id=pk)
form = UpdateAccountForm(instance=Account)
if request.method == 'POST':
form = CreateAccountForm(request.POST, instance=Account)
if form.is_valid():
form.save()
*** Do something here
return("Somehwere")
[...]
Now I'm asking myself, if it's possible - while updating the "Account" - to update the "Person" and - let's say for example - add one of the two "values_..." into the "value_person"? The connection should be there via the "ForeignKey", right? I think I should also mention, that I'm talking about my default database!
I'm aware that this might be a bad example, but it's just so that I can understand the system behind this - hopefully existing - function!
Of course, you can do this with the code below. However, as far as I know, there is no function that does this. foreign key relations
account_instance = Account.object.get(id=1)
person = account_instance.person
person.value_person += 1
person.save()
For example, if you want it only in view, you can do as in the code below
[...]
account_db = Account.objects.get(id=pk)
form = UpdateAccountForm(instance=Account)
if request.method == 'POST':
form = CreateAccountForm(request.POST, instance=Account)
if form.is_valid():
form.save()
person = account_db.person
person.value_person += 1
person.save()
return("Somehwere")
[...]
Or if you want this logic to be executed every time when model is saved, you can do with the overriding the save method of the Account class. overriding model save
class Account():
name = models.CharField()
description = models.Textarea()
person = models.ForeignKey(Person, null=False, blank=False, on_delete=models.CASCADE)
value_a = models.IntegerField()
value_b = models.IntegerField()
date_created = models.DateField
def save(self, *args, **kwargs):
self.person.value_person += 1
self.person.save()
super().save(*args, **kwargs) # don't forget to call super method
Also, I don't recommend it but you can use the post save signal. As a note, it is difficult to debug signals.django doc
from django.db.models.signals import post_save
from django.dispatch import receiver
#receiver(post_save, sender=Account)
def increase_person_values(sender, instance, **kwargs):
instance.person.value_person += 1
instance.person.save()

displaying a user tasks

model.py
class Person(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
def __unicode__(self):
return self.user.username
class Task(models.Model):
username = models.ForeignKey(User, on_delete=models.CASCADE)
titre = models.CharField(max_length=100)
date = models.DateField()
objectif = models.CharField(max_length=1000)
theme = models.CharField(max_length=20)
views.py
tasks = Task.objects.filter()
return render_to_response('home.html',{'tasks':tasks})
the problem is it display all the tasks in the table but i want to display just the tasks of the user who is logged in
how can i do that
You just need to filter by the user on request.user
tasks = Task.objects.filter(username=request.user)
Your view function (which you aren't fully displaying) has a request parameter. This parameter can be used to retrieve the current request's user. You should then use that to filter the tasks:
def the_view(request):
# ....
tasks = Task.objects.filter(username=request.user)
return render_to_response('home.html',{'tasks':tasks})
Task.objects.filter(username=request.user)

Associating users with models django

I have a lot of models in model.py -
class Portfolio(models.Model):
company = models.TextField(null=True)
volume = models.IntegerField(blank=True)
date = models.DateField(null=True)
isin = models.TextField(null=True)
class Endday(models.Model):
company = models.TextField(null=True)
isin = models.TextField(null=True)
eop = models.TextField(max_length=100000)
class Results(models.Model):
companies = models.TextField(default=0)
dates = models.DateField(auto_now_add=False)
eodp = models.FloatField(null=True)
volume = models.IntegerField(null=True)
class Sectors(models.Model):
sector_mc = models.TextField(null=True)
class Insector(models.Model):
foundation = models.ForeignKey(Sectors, null=True)
name = models.TextField(null=True)
value = models.FloatField(default=0)
class AreaLineChart(models.Model):
foundation = models.ForeignKey(CompanyForLineCharts, null=True)
date = models.DateField(auto_now_add=False)
price = models.FloatField(null=True)
class Meta:
ordering = ['date']
I have more such models but as you can see from this snippet, they are not in any way related to any user.
Now I want to relate them to a particular user. In the views too, I was not classifying data per user in any way.
I make users from django admin with username and password and also generate a token for those users from admin. I can authenticate via username and password but from there I know I'd need to use permissions but how is what I do not know. Also, I have serializers that are associated to these models, I know I'd have to use permissions there too but again, I don't know how to. As much as I understand it has to be in someway like this-
#api_view(['GET'])
def searched_company_ohlc(request):
if request.method == 'GET':
// User.objects.get('username'=some_user)
//I guess.
qs = SearchedCompanyOHLC.objects.all()
serializer = SearchedCompanyOHLCSerializer(qs, many=True)
return Response(serializer.data)
Also, I'm using angularJS at the front-end that POSTS username and password on a view with POST decorator to verify the credentials. Where to go from here?
in your models.py you can relate user like this for example
from django.contrib.auth.models import User, Group
class Portfolio(models.Model):
owner = models.ForeignKey(User,verbose_name = 'User',related_name='portfolios')
company = models.TextField(null=True)
volume = models.IntegerField(blank=True)
date = models.DateField(null=True)
isin = models.TextField(null=True)
This has nothing to do with permissions.
If you want to associate your model with a user, use a ForeignKey to the user model.

Categories