How to update Django model data - python

I want to know how I can add data to the Django integer field after the ins.save in my code. For example, if the donation field is equal to 3, after the ins.save, I want to add 1 to it and therefore it will be equal to 4. My code is down below.
Donate View:
def donate(request):
if request.method == "POST":
title = request.POST['donationtitle']
phonenumber = request.POST['phonenumber']
category = request.POST['category']
quantity = request.POST['quantity']
location = request.POST['location']
description = request.POST['description']
ins = Donation(title = title, phonenumber = phonenumber, category = category, quantity = quantity, location = location, description = description, user=request.user, )
ins.save()
return render(request,'donate.html')

You can try this.
from django.db.models import F
......
ins.save()
UserDetail.objects.filter(user=request.user).update(donations=F('donations') + 1)
This will increase the donations of request.user by 1 after ins.save()
Also instead of nullable donation field set default value to zero for your IntegerField in your UserDetail model
class UserDetail(models.Model):
donations = models.IntegerField(default=0)

You don't really need a donations field to count the number of donations of a user as it can be done by a query using the Count aggregation function [Django docs]. For example the below query will give you all users and their donation counts:
from django.db.models import Count
# Assuming 'User' is your user model name
users = User.objects.annotate(donation_count=Count('donation'))
for user in users:
print(user.username, user.donation_count)
# If we already have a user instance
donation_count = user.donation_set.count()
Moving further UserDetail appears to be a model that contains extra details about the user, but it has a problem that you are using a Foreign Key, instead of that you should be using a OneToOneField [Django docs] instead, and if you want donations in this model you can add a property that will make that query to this model:
class UserDetail(models.Model):
points = models.IntegerField(blank=True, null = True,)
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
) # A user detail without a user doesn't make much sense, hence no null or blank allowed
#property
def donations(self):
return self.user.donation_set.count()

Related

Fetch relations from ManyToMany Field using Annotation

I have my database here. Where I have 2 users connected to one instance of ChatRoomParticipants with a ManyToManyField.
I'm trying to get list of related users from a ManyToMany Relation Field from ChatRoomParticipants where I don't want to show the currently authenticated user in the list with other fields i.e room present in the model.
Considering user f4253fbd90d1471fb54180813b51d610 is currently logged in and is related to all ChatRooms via ChatRoomParticipants model.
Things I've tried but couldn't get the desired output
chatrooms = list(ChatRoomParticipants.objects.filter(user=user).values_list('user__chatroom_users__user__username', 'room').distinct())
#####
chatrooms = ChatRoomParticipants.objects.filter(user=user).annotate(user!=User(user))
####
chatrooms = Chatrooms.objects.filter(user=user)
rooms = chatrooms.values('user__chatroom_users__user__username').distinct().exclude(user__chatroom_users__user__username=user)
I want an output like
[
{
'user': '872952bb6c344e50b6fd7053dfa583de'
'room': 1
},
{
'user': '99ea24b12b8c400689702b4f25ea0f40'
'room': 2
},
{
'user': 'eecd66e748744b96bde07dd37d0b83b3'
'room': 3
},
]
models.py
class ChatRoom(models.Model):
name = models.CharField(max_length=256)
last_message = models.CharField(max_length=1024, null=True)
last_sent_user = models.ForeignKey(
User, on_delete=models.PROTECT, null=True)
def __str__(self):
return self.name
class Messages(models.Model):
room = models.ForeignKey(ChatRoom, on_delete=models.PROTECT)
user = models.ForeignKey(User, on_delete=models.PROTECT)
content = models.CharField(max_length=1024)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.content
class ChatRoomParticipants(models.Model):
user = models.ManyToManyField(User, related_name='chatroom_users')
room = models.ForeignKey(ChatRoom, on_delete=models.PROTECT)
I think the database design is wrong. Especially, the user field in the ChatRoomParticipants model is defined as ManyToManyField but I think it should be just as ForeignKey because there needs to be the M2M relationship between User and ChatRoom, not between User and ChatRoomParticipants.
class ChatRoomParticipants(models.Model):
user = models.ForeignKey(User, related_name='chatroom_users', on_delete=models.PROTECT)
room = models.ForeignKey(ChatRoom, on_delete=models.PROTECT)
Then the filter function should work.
First you need to get the list of rooms that the current authenticated user is in:
room_ids = list(ChatRoomParticipants.objects.filter(user=user).values_list('room__id', flat=True))
And you get the roommates:
participants = ChatRoomParticipants.objects.exclude(user__id = user.id).filter(room__id__in = room_ids)
if you still want to keep your DB design then check the bellow link for query reference
[https://docs.djangoproject.com/en/4.0/topics/db/queries/#lookups-that-span-relationships]
You can do the query from the User model.
from django.db.models import F
User.objects.exclude(
username=user
).annotate(
room=F(
'chatroomparticipants__room'
)
).filter(room__isnull=False)
Also the != in your annotation you should consider look at the Q class
example,
With that you can do this negation.
from django.db.models import Q
User.objects.filter(
~Q(username=user)
)

How can I overwrite a models.py entry only if the user id is the current user?

I have genome files, and I want each user to be able to upload their own genome file, but they can only have one of them. I want it so that if they try to upload another, then they will just replace the genome and form data for their last entry.
I am using their entries, along with n number of people who use the site (each person also having 1 entry per person) as samples to analyze against that person's genome, so I want to keep a models file full of genomes, names, sex, etc... but only one per user.
Here's my models.py file
from django.db import models
from django.core.exceptions import ObjectDoesNotExist
SEX_CHOICES = (
('M', 'Male'),
('F', 'Female')
)
class Genome(models.Model):
first_name = models.CharField(max_length=25)
last_name = models.CharField(max_length=25)
CHOICES = [('M','Male'),('F','Female')]
sex = models.CharField(max_length=1, choices=SEX_CHOICES, default='M')
genome = models.FileField(upload_to='users/genomes/')
#id = request.user.id
#if id is the current user then replace old data with new data
def __str__(self):
return self.title
and here is my views function
def upload(request):
context = {}
if request.method == 'POST':
form = GenomeForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('My-DNA.html')
else:
form = GenomeForm()
return render(request, 'my-DNA.html', {context})
else:
print("failure")
form = GenomeForm()
return render(request, 'Upload.html', {
'form': form
})
I just want a way to limit the user to one response while still having a list of many genomes from other people to compare it to.
Thanks
You can do that by adding another field in model.
class Genome(models.Model):
first_name = models.CharField(max_length=25)
last_name = models.CharField(max_length=25)
CHOICES = [('M','Male'),('F','Female')]
sex = models.CharField(max_length=1, choices=SEX_CHOICES, default='M')
genome = models.FileField(upload_to='users/genomes/')
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="user")
Here by adding user as a onetoOneField, One User can only create one genome document. If you want ,multiple genome document you can use foreignKey field.
See OneToOne doc : OnoToOne doc
Foreign Key doc: Foreign Key doc
Then you can check in view that user has genome document or not.
If has then simply update or create a new genome document.
You can check by filtering in view:
Genome.objects.filter(user=user).first()
Here filter return a queryset and by calling first() you can get the first document in that queryset or if not found it simply return none.

Django how to concatenate form data before saving to the database

I am building a budgeting web app for many users. The user creates accounts to track different values. The problem is that I cannot make a composite key and need the AccountName to be the primary key.
This poses a challenge. What if users make the same account name? This will happen as some users may make a "Cash" account. My solution to this problem is to name the account in the database the AccountName + the userid. How can I modify the users AccountName in the form to be AccountName + userid?
Desired AccountName examples in the database: Cash1, Cash2
models.py
class Account(models.Model):
DateCreated = models.DateTimeField()
AccountName = models.CharField(max_length= 100, primary_key=True)
UserID = models.ForeignKey(MyUser, on_delete=models.CASCADE)
Type = models.CharField(max_length= 20)
Balance = models.DecimalField(max_digits=19, decimal_places=8)
Value = models.DecimalField(max_digits=19, decimal_places=8)
Views.py
#login_required
def func_AccountsView(request):
# This filters users accounts so they can only see their own accounts
user_accounts = Account.objects.filter(UserID_id=request.user).all()
if request.method == 'POST':
form = AddAccount(request.POST)
if form.is_valid():
account = form.save(commit=False)
account.UserID = request.user
account.AccountName = AccountName + str(request.user) # WHY DOES THIS NOT WORK?
account.save()
return redirect('accounts')
else:
form = AddAccount()
else:
form = AddAccount()
data = {
'form':form,
'data': user_accounts
}
return render(request, 'NetWorth/accounts.html', data)
forms.py
class AddAccount(forms.ModelForm):
''' This is the form that handles additions of an account '''
class Meta:
model = Account
fields = ['AccountName','DateCreated', 'Type', 'Balance', 'Value']
Get AccountName from form input by getting it from cleaned_data then concat with request.user.pk. Don't forget to convert pk value into str otherwise you will getting TypeError exception
....
account.AccountName = form.cleaned_data.get('AccountName') + str(request.user.pk)
account.save()
request.user will not work because it is an object which contains other fields.
Also your AccountName variable does not represent anything thanks to Eby Sofyan's answer
To fix your problem replace,
account.AccountName = form.cleaned_data.get('AccountName') + str(request.user.id)

Is it possible to limit choices in SelectModelField in wtf-peewee

I use flask with flask-peewee and wtfpeewee.
So, I have models like that:
class Category(Model):
name = CharField()
user = ForeignKeyField(User, null=True)
class Record(Model):
value = DecimalField()
category = ForeignKeyField(Category)
user = ForeignKeyField(User)
When I create form for user to add Record, I do it that way:
RecordForm = model_form(Record)
All categories in database are available for choice in field 'Category' of this form, but I need to limit available choices for 'Category' field to a subset of categories that have user field equal None or current (logged in) user. I know how to limit it by query, but how should that be done for a form field?
Sorry to see this just now
You can do this at class definition time:
from wtfpeewee.fields import SelectQueryField
class MyForm(Form):
category = SelectQueryField(query=Category.filter(some_val=other_val)
Alternatively, I believe you can do this at runtime:
my_form = MyForm()
my_form.category.query = Category.filter(user=some_user)

Creating an edit form from model containing Foreignkey?

I am creating an app, where I am storing employee's complete information, now the problem with my development is that I am entering dependents of the employee in a manner that the Person which he adds as a dependent gets a entry in the Person model.
Dependent and DependentRelationship Model Look Like:
class Dependent(Person):
"""Dependent models: dependents of employee"""
occupation = models.CharField(_('occupation'), max_length=50, null=True,
blank=True)
self_dependent = models.BooleanField(_('self dependent'))
class DependentRelation(models.Model):
"""Dependent Relation Model for Employee"""
employee = models.ForeignKey(Employee, verbose_name=_('employee'))
dependent = models.ForeignKey(Dependent, verbose_name=_('dependent'))
relationship = models.CharField(_('relationship with employee'),
max_length=50)
class Meta:
ordering = ('employee', 'dependent',)
unique_together = ('employee', 'dependent' )
I am using a ModelForm to enter the data for the dependent this is the form for adding dependent:
class DependentForm(forms.ModelForm):
relationship = forms.CharField(_('relationship')) # TODO: max_length??
class Meta:
model = Dependent
I wanted to show all the Dependent's Information as well as the relationship with the employee, in the edit form. So is there a possible view.
Any suggestions or links can help me a lot.......
Thanks in Advance.....................
#login_required
def edit_dependents(request, id):
employee = request.user.get_profile()
try:
dependent = employee.dependent.get(id=id)
except Dependent.DoesNotExist:
messages.error(request, "You can't edit this dependent(id: %s)." %id)
return HttpResponseRedirect(reverse('core_show_dependent_details'))
dependent_relation = DependentRelation.objects.get(dependent=dependent, employee=employee)
if request.method == "POST":
form = DependentForm(data=request.POST, instance=dependent)
if form.is_valid():
dependent = form.save(commit=False)
dependent_relation = DependentRelation.objects.get(dependent=dependent, employee=employee)
dependent_relation.relationship = form.cleaned_data['relationship']
try:
dependent_relation.full_clean()
except ValidationError, e:
form = DependentForm(data=request.POST)
dependent.save()
dependent_relation.save()
return HttpResponseRedirect(reverse('core_show_dependent_details'))
else:
form = DependentForm(instance=dependent,
initial={'relationship': dependent_relation.relationship})
dictionary = {'form':form,'title':'Edit Dependents',}
return render_to_response('core/create_edit_form.html',dictionary, context_instance = RequestContext(request))
As I have defined my model form in my question, I created an edit form from the same with passing two arguments one is the instance of the dependent person with the query as
dependent = employee.dependent.get(id = id)
where the second id is the dependent's id.
Secondly I saved the relationship in the DependentRelationship model with all its attributes, having the value of relationship, and dependent from the ModelForm.
So in this way I was able to create the edit form for my app. After a long search which is working good.

Categories

Resources