User groups in Django - django

I just lost myself a little, and I'm stuck on this one.
I have a model which has a group field :
class CalendarGroups(models.Model):
GRP_CALS = (
('Grp1', 'Grp1'),
('Grp2', 'Grp2'),
('Test', 'Test'),
)
name = models.CharField(max_length=155, choices=GRP_CALS, blank=True, null=True)
def __str__(self):
return self.name
class Meta:
...
class CalendarMaster(models.Model):
created_by = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
date_created = models.DateTimeField(auto_now_add=True)
group = models.ForeignKey(CalendarGroups, on_delete=models.CASCADE)
date_valid = models.DateTimeField(null=True, blank=True)
I just want to check, if the User's group matches the Calendar group - some context will be rendered.
My views :
#login_required(login_url='registration/login')
def add_event(request, pk):
opp = get_object_or_404(OpportunityList, pk=pk)
opp_locked = get_object_or_404(Locked, pk=pk)
user = User.objects.get(username=request.user.username)
...
user_groups = request.user.groups.values_list('name', flat=True)
events_all = Events.objects.all()
calendars = Calendar.objects.all()
form = ...
if request.method == 'POST':
form = ...(request.POST or None)
if form.is_valid():
event_form = form.save(commit=False)
event = Events.objects.create(
event_name=opp_locked.type + '/' + str(opp.oppc_place) + '/' + opp.oppc_client_name,
event_comment=form.cleaned_data['event_comment'],
...
)
...
event.save()
messages.success(request, '...' + ...)
return redirect('...')
context = {
'form': form,
'opp': opp,
'events': events_all,
"calendars": calendars,
"today": datetime.now().date(),
"user": user,
"user_groups": user_groups,
}
return render(request, '...', context)
I need something like :
{% if user_group == calendar_group %}
But somehow, I cant manage it -.-
PS. User groups are the same as CalendarMaster's

I just added another field which is linking those two tables. Since there wasn't any relation to those two tables, it was impossible to link them by any chance.

Related

Django view in array

I have 2 tables (posts, upvoted) that I am working within and am looking to see if a post has been upvoted already and if it has, replace the upvote arrow with a filled arrow. In my view, I am already sending over the Upvote object to my template and am trying to check if the post.id exists within the upvoted table. I tried the code below but it didn't work. How would I do it?
Model:
class Post(models.Model):
user = models.ForeignKey(User, related_name="posts", on_delete=models.DO_NOTHING)
body = models.CharField(max_length=255)
image = models.ImageField(
default="onebyone.png", upload_to="images/", blank=True, null=True
)
created_at = models.DateTimeField(auto_now_add=True)
post_karma = models.IntegerField(default=0, blank=True, null=True)
comment_count = models.IntegerField(default=0, blank=True, null=True)
def __str__(self):
return f"{self.user.username} - {self.created_at.strftime('%Y-%m-%d')} - {self.body[:30]}"
class Upvoted(models.Model):
user = models.ForeignKey(User, related_name="upvoted", on_delete=models.CASCADE)
post = models.ForeignKey(Post, related_name="upvoted", on_delete=models.CASCADE)
upvoted_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return (
f"{self.user.username} - {self.post.user.username} - {self.post.body[:30]}")
View:
#login_required
def dashboard(request):
# form = PostForm(request.POST or None)
# if request.method == "POST":
form = PostForm(request.POST, request.FILES)
if form.is_valid():
img = form.cleaned_data["image"]
body = form.cleaned_data["body"]
if img is None:
img = "images/onebyone.png"
post = Post.objects.create(user=request.user, image=img, body=body)
post.save()
return redirect("posty:dashboard")
sorting = request.GET.get("sort")
ordering = {
"date_sort": "-created_at",
"karma_sort": "-post_karma",
"comment_sort": "-comment_count",
None: "-created_at",
}
# followed_posts = Post.objects.filter(
# user__profile__in=request.user.profile.follows.all()
# ).order_by("-created_at")
followed_posts = Post.objects.filter(
user__profile__in=request.user.profile.follows.all()
).order_by(ordering[sorting])
# get current date_time
now = datetime.now()
return render(
request,
"posty/dashboard.html",
{"form": form, "posts": followed_posts, "comment": Comment, "now": now, "upvote" : Upvoted, "downvote" : Downvoted},)
{% if post.id in upvote.post_id.all %}
First, don't send your Model objects in context, you must do the queries in your view, then send the results to context.
Second:
You can use annotate() and Exists() for that.
from django.db.models import Exists, OuterRef
followed_posts = (
Post.objects.filter(
user__profile__in=request.user.profile.follows.all()
)
.annotate(
is_liked_by_user=Exists(
Upvoted.objects.filter(post_id=OuterRef('pk'), user=request.user)
)
)
.order_by(ordering[sorting])
)
Then in your template:
{% if post.is_liked_by_user %}
... put whatever you want here.
{% endif %}

model form is not saving in django it is telling user can not be nul

i crated a model name address and connected with user by foreign key so a user can have multiple address but it is not saving i want form to take that user id to save but i don't how to do that
here is my models.py
class Address(models.Model):
phoneNumberRegex = RegexValidator(regex = r"^\d{10,10}$")
pincodeRegex = RegexValidator(regex = r"^\d{6,6}$")
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='address')
reciever_name = models.CharField(max_length=200, blank=False)
phone_no = models.CharField(validators = [phoneNumberRegex], max_length = 10, blank=False)
alt_phone_no = models.CharField(validators = [phoneNumberRegex], max_length = 10, blank=True)
state = models.CharField(max_length=50, choices=state_choice, blank=False)
pincode = models.CharField(validators = [pincodeRegex], max_length = 6, blank=False)
eighteen = models.CharField(blank=False, choices=eighteen_choice, default='Yes', max_length=4 )
city = models.CharField(max_length=100, blank=False)
address = models.CharField(max_length=500, blank=False)
locality = models.CharField(max_length=300, blank=True)
joined_date = models.DateTimeField(default=timezone.now,editable=False)
update_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.user.username
my views.py
#login_required
def add_address(request, username):
if request.method == 'POST':
form = Addressform(request.POST)
if form.is_valid():
form.save()
return redirect('accounts:home')
else:
form = Addressform()
return render(request, 'add_address.html', {'form': form})
my form.py
class Addressform(forms.ModelForm):
class Meta:
model = Address
fields = '__all__'
exclude = ['user', 'joined_date', 'updated_at']
labels = {
'reciever_name':'Reciever Name',
'phone_no':'Phone No',
'alt_phone_no':'Alternate Phone No',
'state':'State/Union Territory',
'pincode':'Area Pincode',
'eighteen':'Is reciever is 18+',
'city':'City',
'address':'Address',
'locality':'Locality',
}
widgets = {
'eighteen': forms.RadioSelect()
}
what i want is in user field it take that user who his login automatically but i don't understand how i can achieve that
since you are excluding the user field from the form, it gets a null value on the post request. With a foreign key you cannot have a null field in the database. You have 2 options:
1) Add the request user
#login_required
def add_address(request, username):
if request.method == 'POST':
form = Addressform(request.POST)
if form.is_valid():
form = form.save(commit=False)
form.user = request.user
form.save(commit=True)
return redirect('accounts:home')
else:
form = Addressform()
return render(request, 'add_address.html', {'form': form})
This will add the primary key of the user who is submitting the form as the foreign key of the address and hence associate the user with the address.
2) Allow user to select the user to associate with the address (not suggested)
The alternative method is to allow the user to select the user you want to associate with the address but it is not suggested as any user can associate any user with a particular address.
class Addressform(forms.ModelForm):
class Meta:
model = Address
fields = '__all__'
exclude = ['joined_date', 'updated_at']
labels = {
'reciever_name':'Reciever Name',
'phone_no':'Phone No',
'alt_phone_no':'Alternate Phone No',
'state':'State/Union Territory',
'pincode':'Area Pincode',
'eighteen':'Is reciever is 18+',
'city':'City',
'address':'Address',
'locality':'Locality',
}
widgets = {
'eighteen': forms.RadioSelect()
}

Foreign Key Constraint Failure - Django. Manual assignment of Foreign Key to Model via POST Request

I'm working on a timesheet based system currently. I am getting a Foreign Key constraint failure when I am trying to assign the foreign key of one model to the other one.
Here are the two models
class Timesheet(models.Model):
id = models.CharField(primary_key=True, max_length=50, blank=True, unique=True, default=uuid.uuid4)
First_Name = models.CharField(max_length=32)
Last_Name = models.CharField(max_length=32)
Date_Created = models.DateField(auto_now_add=True)
Creator = models.ForeignKey(User, on_delete=models.DO_NOTHING)
Approved = models.BooleanField(default=False)
Company_Relationship = (
('Supplier', 'Supplier'),
('Contractor', 'Contractor'),
('Employee', 'Employee')
)
Worker_Type = models.CharField(max_length=32, choices=Company_Relationship)
Total_Days_Worked = models.DecimalField(decimal_places=2, max_digits=3)
class Meta:
ordering = ['-id']
#unique_together = ['Creator', 'Work_Week']
def get_absolute_url(self):
return reverse('timesheet-detail', kwargs={'pk': self.pk})
class InternalSheet(models.Model):
id = models.CharField(primary_key=True, max_length=50, blank=True, unique=True, default=uuid.uuid4)
Timesheet_id = models.ForeignKey(Timesheet, on_delete=models.DO_NOTHING)
Working_For = (
('7', 'Seven'),
('i', 'intelligent'),
('S', 'Sata'),
)
iPSL = (
('R16.1', 'Release 16.1'),
('R16', 'Release 16')
)
Company_name = models.CharField(max_length=5, choices=Working_For)
Company_name_change = models.CharField(max_length=5, choices=Working_For)
Internal_Company_Role = models.CharField(max_length=10, choices=iPSL)
DaysWorked = models.DecimalField(decimal_places=2, max_digits=3)
Managers = (
('GW', 'Greg Wood'),
('JC', 'Jamie Carson')
)
ManagerName = models.CharField(max_length=8, choices=Managers)
Approved = models.BooleanField(default=False)
def get_absolute_url(self):
return reverse('sheet-detail', kwargs={'pk': self.pk})
My issue is that I am getting a foreign key failure using this post request.
class TimesheetCreateView(LoginRequiredMixin, CreateView):
"""
Creates view and send the POST request of the submission to the backend.
"""
def get(self, request, *args, **kwargs):
internal_form_loop = create_internal_form_for_context()
context = {'form': CreateTimesheetForm(), 'UserGroup': User()}
context.update(internal_form_loop)
print("new", context)
return render(request, 'create.html', context)
def post(self, request, *args, **kwargs):
form = CreateTimesheetForm(request.POST)
internal_form_1 = CreateInternalSheetForm(request.POST)
if form.is_valid():
print("forms valid")
external_timesheet = form.save(commit=False)
print("self", self.request.user)
print("id", Timesheet.id)
external_timesheet.Creator = self.request.user
external_timesheet.save()
else:
print("Error Here")
if internal_form_1.is_valid():
print("Internal form valid")
internal = internal_form_1.save(commit=False)
internal.Timesheet_id_id = Timesheet.id
internal.id = uuid.uuid4()
internal.save()
return HttpResponseRedirect(reverse_lazy('timesheet-detail', args=[Timesheet.id]))
return render(request, 'create.html', {'form': form, 'UserGroup': User()})
It is failing on the line internal.save(). If I print the line internal.Timesheet_id_id I get a value like this, <django.db.models.query_utils.DeferredAttribute object at 0x000001580FDB75E0>. I'm guessing this is the issue? I need the actual Foreign key and not the location of that object. How do I do this. Thanks.
Figured out the issue, I had to replace the lines
internal.Timesheet_id_id = Timesheet.id
internal.id = uuid.uuid4()
internal.save()
with
internal.Timesheet_id_id = Timesheet.objects.get(id=external_timesheet.id)
internal.save()

show only one type of user in forms using django

I'm trying to create an appointment app using Django
but when I add the form it show me all the users
how can i change that to only one type of user
and make the user who register the appointment him self
this is my models.py
class User(AbstractUser):
STATUS_CHOICES = (('paitent', 'paitent'), ('Doctor', 'Doctor'), ('reception', 'reception'), ('temporary', 'temporary'))
STATUS_CHOICES_2 = (('yes', 'yes'), ('no', 'no'))
type_of_user = models.CharField(max_length=200, choices=STATUS_CHOICES, default='paitent')
allowd_to_take_appointement = models.CharField(max_length=20, choices=STATUS_CHOICES_2, default='yes')
def is_doctor(self):
if self.type_of_user == 'Doctor':
return True
else:
return False
def is_paitent(self):
if self.type_of_user == 'paitent':
return True
else:
return False
class Appointement_P(models.Model):
user_ho_add = models.ForeignKey(User, on_delete=models.CASCADE, related_name='user_ho_add_appointement')
patient = models.ForeignKey(User, null=True, on_delete=models.SET_NULL, related_name='paitent_app')
doctor = models.ForeignKey(User, on_delete=models.CASCADE, related_name='doctor_app')
date = models.Field(null=True, blank=True, default=timezone.now)
start_time = models.TimeField(null=True, blank=True, default=timezone.now)
end_time = models.TimeField(null=True, blank=True, default=timezone.now)
and this is my fomrs.py
class AppointementForm(forms.ModelForm):
class Meta:
model = Appointement_P
fields = ('doctor', 'date', 'start_time',)
and this is my fucntion in the views.py
def create_appointement_p(request):
user = User()
form_appointement = AppointementForm()
if request.method=='POST':
if request.user.is_paitent():
form_appointement = AppointementForm(request.POST or None)
if form_appointement.is_valid():
form_app = form_appointement.save(commit=False)
form_app.save()
messages.success(request, 'appointement added')
else:
messages.error(request, 'Error')
return render(request,'appointement/add_appointement1.html',)
else:
return HttpResponseRedirect(reverse("create_appointement_D"))
return render(request,'appointement/add_appointement1.html',{'form':form_appointement})
and this is the html file
<body>
<div class="container">
{{ form }}
{% csrf_token %}
<button>
ok
</button>
</form>
</div>
</body>
the problem is in the doctoral field, it show me all the user how can I change that to only users that have a type of doctors
how can I make the user_ho_add automatically the one ho register this appointment?
how can I make the end time of the appointment the start_time + 30 min?
For filtering the doctor field you can customize it in you ModelForm class, like this:
# import your User model first
class AppointementForm(forms.ModelForm):
doctor = forms.ModelChoiceField(queryset=User.objects.filter(type_of_user='Doctor'))
class Meta:
model = Appointement_P
fields = ('doctor', 'date', 'start_time',)
Then for filling the user_ho_add field, just add the user before saving the form_app instance, like this:
def create_appointement_p(request):
...
if form_appointement.is_valid():
form_app = form_appointement.save(commit=False)
form_app.user = request.user # user added here
form_app.save()
messages.success(request, 'appointement added')
...
Bonus tip: for the is_paitent and is_doctor methods, you can simply return the comparison, since the result is already a boolean, like this:
def is_doctor(self):
return self.type_of_user == 'Doctor'
def is_paitent(self):
return self.type_of_user == 'paitent'
UPDATE
As requested in the comment, for adding end_time = start_time + 30min you first need to import the timedelta class from the datetime library.
from datetime import timedelta
# your other imports
...
def create_appointement_p(request):
...
if form_appointement.is_valid():
form_app = form_appointement.save(commit=False)
form_app.user = request.user # user added here
form_app.end_time = form_app.start_time + timedelta(minutes=30) # end_time added here
form_app.save()
messages.success(request, 'appointement added')
...
Bonus tip 2: If you're using Django 3.1 (or above) you can use the models.TextChoices class to create a cleaner way to reference your choices, like this:
class TypeOfUser(models.TextChoices):
# REFERENCE_VALUE = 'string to save in the field', 'string to display (supports translation)'
PAITENT = 'paitent', 'Patient'
DOCTOR = 'doctor', 'Doctor'
RECEPTION = 'reception', 'Reception'
TEMPORARY = 'temporary', 'Temporary'
class AllowdToTakeAppointement(models.TextChoices):
YES = 'yes', 'Yes'
NO = 'no', 'No'
class User(AbstractUser):
type_of_user = models.CharField(max_length=200, choices=TypeOfUser, default=TypeOfUser.PAITENT)
allowd_to_take_appointement = models.CharField(
max_length=20, choices=AllowdToTakeAppointement.choices, default=AllowdToTakeAppointement.YES
)
def is_doctor(self):
return self.type_of_user == TypeOfUser.DOCTOR
def is_paitent(self):
return self.type_of_user == TypeOfUser.PAITENT
Then you can import the TypeOfUser class for your AppointementForm class:
# import your User model and TypeOfUser
class AppointementForm(forms.ModelForm):
doctor = forms.ModelChoiceField(queryset=User.objects.filter(type_of_user=TypeOfUser.DOCTOR))
class Meta:
model = Appointement_P
fields = ('doctor', 'date', 'start_time',)

Django Form If condition in view.py with 2 instance

TO SAVE DATA that is inputted in form in Django i tried tomake it like this
I put this in my model.py
class Item(models.Model):
CATEGORY = (
('Gudang Kering', 'Gudang Kering'),
('Gudang Basah','Gudang Basah'),
)
name = models.CharField(max_length=200,null= True)
stock = models.IntegerField(default='0', blank=False, null=True)
category = models.CharField(max_length=200,null= True,choices=CATEGORY)
reorderlevel = models.IntegerField(default='0', blank=False, null=True)
maxreorderlevel = models.IntegerField(default='0', blank=False, null=True)
description = models.CharField(max_length=200,null= True, blank= True)
date_created = models.DateTimeField(auto_now_add= True)
tags = models.ManyToManyField(Tag)
def __str__(self):
return self.name
class Issue(models.Model):
STATUS = (
('Pending', 'Pending'),
('Granted','Granted'),
('Denied','Denied'),
)
customer = models.ForeignKey(Customer, null=True, on_delete= models.SET_NULL)
item = models.ForeignKey(Item, null=True, on_delete= models.SET_NULL)
quantity = models.IntegerField(default='0', blank=False, null=True)
date_created = models.DateTimeField(auto_now_add=True, auto_now=False)
status = models.CharField(max_length=200,null= True, choices=STATUS)
Then in view.py i define the form like this
def updateIssue(request, pk):
issue = Issue.objects.get(id=pk)
item = Item.objects.all()
form = UpdateIssueForm(instance=issue)
if request.method == 'POST':
form = UpdateIssueForm(request.POST,instance=issue)
#print ('printing:',request.POST)
if form.is_valid():
instance = form.save(commit=False)
if instance.status == 'Granted':
item.stock -= instance.quantity
instance.save()
item.save()
else:
instance.save()
return redirect('/')
context = {'form':form}
return render(request,'accounts/issue_form.html',context)``
The Goal
if instance == "Granted"
the item.stock will be decreased on the amount of instance.quantity
and will be saved.
else
instance will just be saved without affecting the stock from the 2nd model
The error
item = Item.objects.all()
even when called the item.stock have 0 attribute even when i have input data in database for that table
There is no need to get Item since we can access the Item related to Issue using the Issue object like issue.item. This is just an example from docs:
Article model has a field reporter which is a ForeignKey realted to Reporter model. Using Article object the Reporter object is accessed.
>>> new_article = r.article_set.create(headline="John's second story", pub_date=date(2005, 7, 29))
>>> new_article
<Article: John's second story>
>>> new_article.reporter
<Reporter: John Smith>
>>> new_article.reporter.id
1
Like so, we can access the Item using Issue
def updateIssue(request, pk):
issue = Issue.objects.get(id=pk) # we have our Issue here
form = UpdateIssueForm(instance=issue)
if request.method == 'POST':
form = UpdateIssueForm(request.POST,instance=issue)
if form.is_valid():
instance = form.save(commit=False)
if instance.status == 'Granted':
issue.item.stock -= instance.quantity # access Item by using Issue object's related field with name item
issue.item.save() # save the Item first
instance.save() # then the Issue
else:
instance.save()
return redirect('/')
context = {'form':form}
return render(request,'accounts/issue_form.html',context)