Having trouble with notifications feature in Django - python

Created a notification feature in my django project. I've got all the functionality down and it works except for one thing. I want the template to display a different message depending on what action is committed. All it currently displays is 'The ticket has been updated' instead of 'A new ticket has been assigned to you.' How do I fix this?
Here is what i have so far.
template
<div class="dropdown-content" id="myDropdown">
{% if notifications %}
{% for notification in notifications %}
{% if notification.notification_type == 'created' %}
{{notification.ticket.name}}: A new ticket has been assigned to you.
{% else %}
{{notification.ticket.name}}: The ticket has been updated.
{% endif %}
{% endfor %}
{% else %}
No new notifications
{% endif %}
</div>
models.py for notification
class Notification(models.Model):
OPTIONS = (
('created', 'created'),
('updated', 'updated'),
)
recipient = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, null=True, related_name='notifications')
ticket = models.ForeignKey(Ticket, on_delete=models.SET_NULL, null=True, related_name='notifications')
message = models.TextField()
notification_type = models.CharField(choices=OPTIONS, max_length=15, null=True)
is_read = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True)
signals.py for notification
#receiver(post_save, sender=Ticket)
def create_notification(sender, instance, created, **kwargs):
if created:
notification_type = 'created'
else:
notification_type = 'updated'
assignees = instance.assignee.all()
for assignee in assignees:
Notification.objects.create(recipient=assignee, notification_type=notification_type)
this is createTicket function inside the views.py
#login_required
def createTicket(request):
form = TicketForm()
categories = Category.objects.all()
users = CustomUser.objects.all()
if request.method == 'POST':
category_name = request.POST.get('category')
category, created = Category.objects.get_or_create(name=category_name)
# Retrieve the project object that the ticket should be connected with
project_id = request.POST.get('project')
project = Project.objects.get(id=project_id)
# Retrieve the list of selected users from the form
assignee_ids = request.POST.getlist('assignee')
assignee = CustomUser.objects.filter(id__in=assignee_ids)
ticket = Ticket.objects.create(
host = request.user,
category=category,
project=project,
name=request.POST.get('name'),
status=request.POST.get('status'),
priority=request.POST.get('priority'),
type=request.POST.get('type'),
description=request.POST.get('description'),
)
# Add the selected users to the ticket
ticket.assignee.set(assignee)
ticket.save()
return redirect('ticket', pk=ticket.id)
context = {'form': form, 'categories': categories, 'users': users}
return render(request, 'tickets/ticket_form.html', context)

ticket = Ticket.objects.create(
host = request.user,
category=category,
project=project,
name=request.POST.get('name'),
status=request.POST.get('status'),
priority=request.POST.get('priority'),
type=request.POST.get('type'),
description=request.POST.get('description'),
)
# Add the selected users to the ticket
ticket.assignee.set(assignee)
ticket.save()
This will trigger your signals twice, 1 for create and another one for save.
You don't need the last line, just put
ticket.assignee.set(assignee)
is enough.
Btw when you create a ticket and signal triggers, you don't have any assignee yet, you should actually do it via m2m_changed signal

Related

How to show history of orders for user in Django

I will pin some screenshots of my template and admin panel
I have history of orders in admin panel but when im trying to show title and img of order product in user profile in my template that`s not working and i got queryset
Im sorry for russian words in my site, i can rescreen my screenshots if you need that
models.py
class Order(models.Model):
user = models.ForeignKey(User, on_delete=models.PROTECT, related_name='orders', verbose_name='Заказы',
default=1)
username = models.CharField(max_length=50, verbose_name='Имя пользователя')
email = models.EmailField()
vk_or_telegram = models.CharField(max_length=255, verbose_name='Ссылка для связи', default='vk.com')
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
paid = models.BooleanField(default=False, verbose_name='Оплачено')
class Meta:
ordering = ['-created',]
verbose_name = 'Заказ'
verbose_name_plural = 'Заказы'
def __str__(self):
return 'Заказ {}'.format(self.id)
def get_cost(self):
return sum(item.get_cost() for item in self.items.all())
class OrderItem(models.Model):
order = models.ForeignKey(Order, related_name='order', on_delete=models.CASCADE)
product = models.ForeignKey(Posts, related_name='order_items', on_delete=models.CASCADE)
price = models.DecimalField(max_digits=10, decimal_places=2)
def __str__(self):
return '{}'.format(self.id)
def get_cost(self):
return self.price
views.py
#login_required
def profile(request):
user_orders = Order.objects.filter(user=request.user)
data = {
'user_orders': user_orders,
}
return render(request, 'store/main_pages/profile.html', data)
order history template:
{% for item in user_orders %}
{{ item }}
{{ item.order.all }}
{% endfor %}
Profile template
admin order panel
Create a model for storing the orders. This model should have fields for storing information about the order, such as the total cost, the date the order was placed, and the status of the order.
Create a view that will display the order history for a user. This view should retrieve all of the orders for the logged-in user from the database and pass them to a template.
Create a template to display the order history. This template should loop through the list of orders passed to it by the view and display the relevant information for each order.
Add a URL pattern to your Django project's urls.py file that maps to the view that displays the order history.
Add a link to the order history page in your application's navigation menu or elsewhere on the site.
In user_orders = Order.objects.filter(user=request.user)
you have all of the user's order histories.
when sending these data to the front, don't use {{ item.order.all }}
each of your items is an order.
I found solution, OrderItem has product, which is a ForeignKey for my product with title, content and img
Views.py changed for:
#login_required
def profile(request):
user_orders = Order.objects.filter(user=request.user)
user_order_item = OrderItem.objects.all()
data = {
'user_orders': user_orders,
'user_order_item': user_order_item,
}
return render(request, 'store/main_pages/profile.html', data)
Template:
{% if user_orders %}
{% for item in user_order_item %}
<p>{{ item.product.title }}</p>
<p><img src="{{ item.product.photo.url }}" alt=""></p>
% endfor %}
{% endif %}

Form returning not valid in django

In my django app I have a User model that has a Boolean field of is_manager.
User model in models.py:
class User(AbstractUser):
name = models.CharField(max_length=15, null=True, blank=True)
last_name = models.CharField(max_length=15, null=True, blank=True)
title = models.CharField(max_length=50, null=True, blank=True)
email = models.EmailField(unique=True)
bio = models.TextField(null=True, blank=True)
company = models.ForeignKey(Company, on_delete=models.DO_NOTHING, null=True)
is_manager = models.BooleanField(default=False)
can_assign = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
I've been trying to create an edit page in order for managers and users to be able to change some of their fields.
Regular users should be able to change their bio and title, and the managers can change the can_assign Boolean.
I have a form that deals with the logic of that in forms.py:
class EditUserForm(ModelForm):
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user')
if self.user.is_manager:
super().__init__(**kwargs)
else:
super().__init__(**kwargs)
del self.fields['can_assign']
class Meta:
model = User
fields = ['title', 'can_assign', 'bio']
views.py:
#login_required
def editUser(request, pk):
user = User.objects.get(id=pk)
if request.user.is_manager or request.user == user:
#POST
if request.method == 'POST':
form = EditUserForm(request.POST, instance=user, user=request.user)
if form.is_valid():
form.save()
redirect('user-page', pk)
else:
print('nope')
#GET
form = EditUserForm(user=request.user, instance=user)
context = {'user': user, 'form': form}
return render(request, 'users/user_edit.html', context)
else:
return HttpResponse('<h1>Access Denied</h1>')
template:
{% extends 'main.html' %}
{% block content %}
<form method="POST" action="">
{% csrf_token %}
{{form.as_p}}
<input type="submit" value="Submit">
</form>
{% endblock content %}
for some reason the form.is_valid() method returns False. I have no idea why.
I have tried to use the .errors method on the form and on the form fields. No errors shown.
Thanks for any help!
" Oh! I completely missed that. I think the *args is required because that's how you pass in the request.POST. if you would have an explicit key like myform(data=request.POST) it would have worked because it would be in the *kwargs .. So it was basically failing cause it was acting like you were just initiating a new form, not submitting one –
Nealium
"

How to I make my review model form show the name of the current user when rendered in template

I am trying to create a review form in Django. I have rendered the form, but I would like the form to display the name of the current logged in user to enable me to associate each review with a user.
Here is my model:
class Review(models.Model):
company = models.ForeignKey(Company, null=True, on_delete=models.SET_NULL)
# SET_NULL ensures that when a company is deleted, their reviews remains
reviewers_name = models.CharField(max_length=250, verbose_name='Reviewed By: (Your Name)')
review_text = models.TextField(max_length=500, verbose_name='Your Review: (Maximum of 200 Words)')
rating = Int_max.IntegerRangeField(min_value=1, max_value=5)
date_added = models.DateField('Review Date', auto_now_add=True)
Here is my view:
def submit_review(request):
form = ReviewForm()
if request.method == 'POST':
form = ReviewForm(request.POST)
if form.is_valid:
form.save()
# gets the company that was immediately submitted in the review form
company = request.POST.get('company')
# gets the rating that was immediately submitted in the review form
rating = request.POST.get('rating')
# uses the name of the company submitted to instantiate the company from the Company database
companyone = Company.objects.get(pk=company)
"""
emloys companyone above to retrieve already existing average rating associated with it
adds this to the current rating sent by the user and stores the total back to the average
rating field of companyone
"""
companyone.average_rating = round((int(rating) + int(companyone.average_rating))/2)
companyone.save()
return redirect('review-submitted')
context = {
'form': form
}
return render(request, 'submit-review.html', context)
Here is the form that gets rendered:
class ReviewForm(ModelForm):
class Meta:
model = Review
fields = '__all__'
In template,
{% if user.is_authenticated %}
<p>{{ user.get_username }} </p>
{% endif %}
In views,
request.user.get_username()

create a distinct model option in a dropdown using django

I have created this application but the problem I face now is one that has kept me up all night. I want users to be able to see and select only their own categories when they want to create a post. This is part of my codes and additional codes would be provided on request
category model
class Category(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, default=1,related_name='categories_created')
name = models.CharField(max_length = 120)
slug = models.SlugField(unique= True)
timestamp = models.DateTimeField(auto_now=False, auto_now_add=True)
post model
class Post(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, default=1,related_name='posts_created') #blank=True, null=True)
title = models.CharField(max_length = 120)
slug = models.SlugField(unique= True)
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='category_created', null= True)
addition codes would be provided immediately on request. Thanks
View.py in post app
def create(request):
if not request.user.is_authenticated():
messages.error(request, "Kindly confirm Your mail")
#or raise Http404
form = PostForm(request.POST or None, request.FILES or None)
user = request.user
categories = Category.objects.filter(category_created__user=user).distinct()
if form.is_valid():
instance = form.save(commit=False)
instance.user = request.user
instance.save()
create_action(request.user, 'Posts', instance)
messages.success(request, "Post created")
return HttpResponseRedirect(instance.get_absolute_url())
context = {
"form": form,
}
template = 'create.html'
return render(request,template,context)
Form
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = [
"title",
"content",
"category",
]
html
{% if form %}
<form method="POST" action="" enctype="multipart/form-data">{% csrf_token %}
{{ form|crispy|safe }}
<input type="submit" name="submit" value="Publish">
</form>
{% endif %}
What you need to do is well-described here. Basically, you are using ModelForm which generates the form from your model. Your model doesn't know anything about filtering by user, so you will need to explicitly add a QuerySet to your form that only shows the desired categories. Change your "categories = ..." line to something like:
form.category.queryset = Category.objects.filter(user=user)
form.fields['category'].queryset = Category.objects.filter(user=user)</strike>

Unable to automatically pick foreign key from modelform

I am working on a product app on Python 2.7 / Django 1.7.
I have a model for product namely 'product_profile' and I want to allow my customer (end user) to ask any thing regarding specific products using a form.
However I am unable to allow user to automatically select the product (foreign key) and the customer has to select from a drop-down which quite irrational. I have also assigned the foreign key in url-variable.
here is my code:
MODEL.PY
class ProductProfile(models.Model):
category = models.ForeignKey(Category)
brand = models.ForeignKey(Brand)
product_name = models.CharField(max_length=128)
model_name = models.CharField(max_length=128)
generation = models.CharField(max_length=128)
processor = models.CharField(max_length=128)
ram = models.DecimalField(max_digits=2, decimal_places=0)
hdd = models.DecimalField(max_digits=6, decimal_places=2)
optical_drive = models.CharField(max_length=128)
display = models.CharField(max_length=128)
card_reader = models.CharField(max_length=128)
blue_tooth = models.CharField(max_length=128)
web_cam = models.CharField(max_length=128)
warranty = models.CharField(max_length=128)
price = models.DecimalField(max_digits=9, decimal_places=2)
condition = models.TextField()
product_image = models.ImageField(upload_to=update_Product_image_filename)
post_date = models.DateTimeField(db_index=True, auto_now_add=True)
# Override th __unicode__() method to return out something meaningful!
def __unicode__(self):
return self.product_name
class Customer_ps_contact(models.Model):
name = models.CharField(max_length=128)
email = models.EmailField(max_length=75)
subject = models.CharField(max_length=128 )
product = models.ForeignKey(ProductProfile)
message = models.TextField()
phone_regex = RegexValidator(regex=r'^\+?1?\d{9,15}$', message="Phone number must be entered in the format:
'+999999999'. Up to 15 digits allowed.")
phone_number = models.CharField(validators=[phone_regex], blank=True, max_length=15) # validators should be a
list
def __unicode__(self):
return self.name
FORM.PY
class Customer_ps_contactForm(forms.ModelForm):
class Meta:
model = Customer_ps_contact
product = forms.ModelChoiceField(queryset=ProductProfile.objects.all(),
widget=forms.HiddenInput())
fields = ('name','email', 'product','subject','message', 'phone_number')
VIEWS.PY
def product_inquiry(request, product_id):
product = ProductProfile.objects.get(pk=product_id)
if request.method == 'POST':
#form = Customer_ps_contactForm(request.POST, initial = {'product': product})
#form = Customer_ps_contactForm(initial = {'product': product.id})
form = Customer_ps_contactForm(request.POST)
if form.is_valid():
form_data_dict = form.cleaned_data
print form_data_dict['product']
mail_customer_enquriy(form_data_dict) # Function to send email to admin
thank_u_customer(form_data_dict) # Function to send email to customers
form = form.save(commit=False)
form.product = product
form.save()
return home(request)
else:
print ("form is not valid")
print (form.errors)
else:
form = Customer_ps_contactForm()
context_dict = {'form':form, 'product': product}
return render(request, 'product/product_inquiry2.html',context_dict)
URL Patterns
urlpatterns = patterns('',
url(r'^inquiry/(?P<product_id>\d+)/$', views.product_inquiry, name='price'), # Only relevent url given
)
Template : product_inquiry2.html
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block body_block %}
{% block title %}Product Inquiry{% endblock %}
<div class="row">
<div class="col-md-10 col-md-offset-1">
<h2 style="font-weight:bold">Enquiry regarding '{{product.product_name}}'</h2>
<hr>
<form id="contact_form" method="post" action=""/>
{% csrf_token %}
{{ form | crispy }}
<input class="btn btn-primary pull-right " type="submit" name="submit" value="Submit the Message" />
</form>
</div>
</div>
{% endblock %}
What should I do?
You know what the product is from the id in the url, so there's no need to include it in your form.
To check that the product exists in the database, you can use the get_object_or_404 shortcut.
def product_inquiry(request, product_id):
product = get_object_or_404(ProductProfile, pk=product_id)
Then leave out 'product' from your list of fields, and remove the ModelChoiceField with hidden input widget.
class Customer_ps_contactForm(forms.ModelForm):
class Meta:
model = Customer_ps_contact
fields = ('name','email','subject','message','phone_number')
You are already setting the product when you save it, but it would be clearer to use the variable name instance to make it clearer what's going on. If you change your mail_customer_enquriy and thank_u_customer methods to use the instance instead of cleaned_data, then you won't have to do anything with form.cleaned_data.
if form.is_valid():
instance = form.save(commit=False)
instance.product = product
instance.save()
mail_customer_enquriy(instance) # Function to send email to admin
thank_u_customer(instance) # Function to send email to customers
return home(request)

Categories

Resources