Django: how to add constraints on the foreign key dashboard - django

I have the model below:
class Account(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE)
class AccountCreate(generics.ListCreateAPIView):
def get_queryset(self):
return Account.objects.filter(owner=self.request.user)
serializer_class = AccountSerializer
I want to create an account of which the owner is the same as the request.user. But when I tried to create a new account, the dashboard displayed all the users. How to make the choices only be the request.user?
As it is shown in the image with the red circles below, the owner could be wz, but I only want it to be victor.

If there is only one choice, why are you making this a field on the form in the first place? If you remove the owner field from the form, and automatically set the user as the owner in the view, wouldn't that be easier for the user, and less work for you? Furthermore, if the whole form is just that one question (and if this question has only one possible answer), wouldn't it be easier to process object creation in the view, when a button is pressed or something?

Related

How can I make an attribute associate automatically with User? django

I'm making a simple website using django.
I've added a 'Comment' model to make a comment section on a blog post. I'd like to print out each of the 'date_added', 'text', and 'owner' attributes in html.
class User_Comment(models.Model):
topic = models.ForeignKey(Topic, on_delete=models.CASCADE)
text = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.text
I have problems with the 'owner' attribute.
owner = models.ForeignKey(User, on_delete=models.CASCADE)
if I try to make migrations with it, Django asks me to provide a default value.
It is impossible to change a nullable field 'owner' on user_comment to non-nullable
without providing a default. This is because the database needs something to populate
existing rows.
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows with a null value for
this column)
2) Ignore for now. Existing rows that contain NULL values will have to be handled
manually, for example with a RunPython or RunSQL operation.
3) Quit and manually define a default value in models.py.
If I add 'blank=True', 'null=True' parameters to the onwer attribute,
the attribute works but it doesn't automatically associate with the owner when adding a comment. So I have to go to the admin to designate the comment manually to its owner.
owner = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True)
What'd be the best solution for this ? I'd like to print the 'owner' attribute in html automatically without having to handle it manually.. Thank you so much for your time.
It may be helpful to explain exactly what has happened here.
You have added an additional field, owner, to an existing Comment model. Because there were already some existing comments, the migration process (that updates Django's understanding of the model in the database) needs to know what to do with the existing comment records that currently have no owner.
This is a one-time process purely to handle the existing records.
However, when you create a new comment, you'll also need to handle who the owner is so the model field gets filled automatically. Let's say you have a model form that takes in user comments and your view tests if a comment is being posted:
form = CommentForm(request.POST or None)
if request.method == "POST" and form.is_valid:
#create an uncommitted version of the form to add fields to
form_uncommitted = form.save(commit=False)
#here we explicitly assign the owner field to the user that made the request
form_uncommitted.owner = request.user
#then save the form data plus our added data
form_uncommitted.save()

How can I access a value from one model and pass to another model in Django?

I have one model called Weight (filled by User input/choice) and another called Enterprise.
class Weight(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="weights")
weight_of_history = models.IntegerField(null=True, blank=True)
class Enterprise(models.Model):
...
The weight is saved, one per user, and replaced everytime the user choose new one.
Inside the Enterprise class, I am creating an property that must get the "weight_of_history" (depending on the user, who has chosen the weight) from Weight class, but the models have no Foreign key or related name between them.
class Enterprise(models.Model):
...
#property
def ranking(self):
weight_of_history = <-- HERE I NEED TO TAKE WEIGHT_HISTORY FROM THE FIRST MODEL
THEN I COULD CALCULATE
How could I do that? Thank you!
You can use django's powerful query functionality and fetch the required objects from the db. Here are the docs that might help you with that. Django docs are amazing, so I would recommend that you read up on queries, models, and forms to have easier time with you project.
For your example we can fetch all the weights for the user in one query by filtering the weights by user. In fact, django ORM allows for chaining filters and you can create really sophisticated queries
class Enterprise(models.Model):
...
#property
def ranking(self):
weight_of_history = Weight.objects.filter(user=some_user)
If you do not know the user beforehand, then you can do inside the view and grab the user that makes the request and filter using this user:
#views.py
user_making_request = request.user
weight_of_history = Weight.objects.filter(user=user_making_request)

Django how to implement a one-to-many self-dependent foreign key

I am implementing a User referral system, which existing users can refer other people to register an account with the link they provided. After the new user registers, the new user will be stored to the field 'referred_who' of the existing user.
I have tried using the following method:
class CustomUser(AbstractBaseUser):
...
referred_who = models.ManyToManyField('self', blank=True, symmetrical=False)
class ReferralAward(View):
def get(self, request, *args, **kwargs):
referral_id = self.request.GET['referral_id']
current_referred = self.request.GET['referred']
// referrer
user = get_user_model().objects.filter(referral_id=referral_id)
// user being referred
referred_user = get_user_model().objects.filter(username=current_referred)
for item in user:
previous_referred = item.referred_who
previous_referred.add(referred_user[0])
user.update(referred_who=previous_referred)
And I got the following error:
Cannot update model field <django.db.models.fields.related.ManyToManyField: referred_who> (only non-relations and foreign keys permitted).
I am not sure if this method even works. I have check the Django Admin backend and I realized the 'Referred who' field actually contains all the users. It seems that it only highlightes the user being referred instead of only showing the referred users.
Also, I tried to access the 'referred_who' field in the back-end and it returns 'None'.
Is there a way to stored the users in the 'referred_who' field so that I can see all of the user being referred and access them in the back-end? For instance:
referral_id = self.request.GET['referral_id']
user = get_user_model().objects.filter(referral_id=referral_id)
print(user[0].referred_who)
Can someone show me a better way to do it? Thanks a lot!
You ask how to create a 1-Many field, but in your models you're trying to create m2m. Just change field to FK.
referred_who = models.ForeignKey('self', blank=True).
In case you need to have multiple fks to the same model, you need to specify related_name as well. You can use name of the field for it. More in docs.

django model attribute field empty list

I'm trying to build an online forum. Right now, my forum model has several attributes and one of it is "owner", which is a ForeignKey to the user that created this forum. It also has another attribute "passcode" which makes sure that whenever an owner creates a forum, he/she has to type a passcode so that only others with the right passcode can join the forum. Now, I am trying to implement a new function such that users can choose to join existing forums; however, I am stuck.
1) My first issue is that in order to create a custom permission, I first need another model attribute that contains a list of the permissioned users. I was thinking of having a model attribute as an empty list, permissioned_users = [], so that whenever a user requests to join a forum and has the right passcode, his/her username will be appended to the list and then in my views.py I can use #user_passes_test to check if the request.user.username is in the list. However, i'm not sure if "students = []" will work such that i can do "anyparticularinstance".students.append("his name") will work.
2) How do i create a join forum function? I have fully implemented a create forum function but how do I allow users to join an existing forum? Thank you!
One Way you can achieve the permissions is by defining a Boolean field in your model, for example:
class Forum(AbstractBaseUser):
username=models.CharField(max_length=20,unique=True)
name = models.CharField(max_length=20)
email = models.EmailField(max_length=254,null=True,blank=True)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
By extending the AbstractBaseUser in Django you can define custom permissions for users.Either from the default Admin provided by Django or may be your own custom admin, you can add or remove permissions to a particular user. For more information you can see the following link Django AbstractBaseUser
You can achieve your objective by using textfield, and then appending at the end of the textfield everytime you update the field.
Model:
permissioned_users = models.TextField(blank=True, null=True)
View:
foo = Forum.objects.get(id=id)
temp = foo.permissioned_users
temp = temp+" username"
foo.permissioned_users = temp
foo.save()
Obviously you have to do some more work, ex. when you want to check which user is given permission, you split the string using whitespace hence str.split(), then you can easily iterate through it and make your checks.

Django AttributeError Modifying Field Without Tracking Change History

I am currently running a production Django webapp that holds historic item information using the SimpleHistory feature.
I have a navigation bar that displays all current revisions of all items to click on and view their separate pages. That being said, I wanted to have the ability to select which items to show/hide in the navigation bar by updating a boolean field on the item admin pages.
So, I modified the item models to have a field to do such:
class Item(models.Model)
field1 = models.CharField()
field2 = models.CharField()
...
hide_item = models.BooleanField('Item hidden:', default=True) #don't want history on this field
reason_for_change = models.CharField()
changed_by = models.ForeignKey(User, null=True)
accepted_by = models.ForeignKey(User, null=True)
accepted_date = models.DateTimeField()
history = HistoricalRecords()
def __unicode__(self):
return self.name
def save(self, *args, **kwargs):
super(Item, self).save(*args, **kwargs)
#property
def _history_user(self):
return self.changed_by
#_history_user.setter
self.changed_by = value
After making the migrations, this field showed up in the admin pages to my delight, but unfortunately I am not able to modify this field without receiving the following error:
AttributeError: can't set attribute
C:\Python27\lib\site-packages\simple_history\admin.py in save_model, line 151
151. obj._history_user = request.user
I think it might have to do with the fact that all changes to item field need to be tracked using the SimpleHistory feature, but for this particular field I don't want to track and store the history of its changes, I just want to be able to enable and disable at will in the admin page.
I also noticed, that if I make a new instance of an Item on the webapp and check the value of hide_item on the admin item page, it is False when it should be True by default. On the contrary, if I attempt to add a new Item instance within the admin page, hide_item is set to True by default as expected...
Right now I think my best solution might be to make another model that holds hide/display information for all items and keep it separate from the item models.
Wondering if anyone might now how to accomplish this.
Thanks
Might not be the most elegant way to do it, but I ended up making a separate model that stores show/hide information and syncs with the item to be displayed.
I did this using a BooleanField for the show/hide and a readonly OneToOne(Item) field to sync with the item I want to display.
Worked well.