Django many to many field data rendering - html

I wanted to create a blog site where an author and editor can both have the edit option and the editors will be assigned by author. Now my model field looks like this :
class Editor(models.Model):
name = models.OneToOneField(Author, on_delete=models.CASCADE, null=True, blank=True)
class Blog(models.Model):
title = models.CharField(max_length=150, null=True, blank=True)
author = models.ForeignKey(Author, on_delete=models.CASCADE, null=True, blank=True)
editor = models.ManyToManyField(Editor, blank=True)
date_created = models.DateTimeField(auto_now_add=True)
article = models.TextField(blank=True, null=True)
genre = models.ManyToManyField(Genre, blank=True)
def __str__(self):
return self.title
and views.py :
def blog(request, pk):
if request.user.is_authenticated:
blogs = Blog.objects.get(id=pk) //for dynamic url
editors = Editor.objects.all()
context = {'blogs':blogs,'editors':editors}
return render(request, 'blog/blog.html', context)
then I wanted to check if the person who is accessing if author or editor or not, so I written an if condition :
{% if request.user.author == blogs.author or blogs.editor %}
Edit
{% endif %}
but unfortunately the edit button can be accessed by everyone. what should I do?

First of all.
{% if request.user.author == blogs.author or blogs.editor %}
Edit
{% endif %}
In this piece of code, the condition is not very good defined. My suggestion is that you make this in this way:
{% if request.user.author == blogs.author or request.user.author == blogs.editor %}
Edit
{% endif %}
This is one suggestion.
Now another posibility is to use JavaScript.
In order to do that, I give you some code example of my own.
<script type="text/javascript">
var editor = '{{user.author.editor}}'
if (editor == 'False'){
document.getElementById('edit').innerHTML = ''
}
</script>
In this code, I'm defining that if the user is not a editor, I will not hide the element (In html) with id 'edit'. So in your template, set an id to your element.
<a id="edit" href="#" class="btn btn-warning">Edit</a>
For this, you will have to set a boolean field in your model.
You can do it like this:
class Editor(models.Model):
name = models.OneToOneField(Author, on_delete=models.CASCADE, null=True, blank=True)
editor = models.Boolean()

Related

How to make dropdown with <options> tag in html from choices in django model?

I have authentication app with
models:
LIVING_COUNTRIES = [
('AFGANISTAN', 'Afganistan'),
('ALBANIA', 'Albania'),
('ALGERIA', 'Algeria'),
('ANGORRA', 'Andorra'),
('ANGOLA', 'Angola')]
class Employee(models.Model):
first_name = models.CharField(max_length=100, blank=True)
last_name = models.CharField(max_length=100, blank=True)
username = models.CharField(max_length=30, blank=True)
email = models.EmailField(max_length=140, blank=True)
# phone_number = PhoneNumberField(null=True)
date_of_birth = models.DateField(blank=True, default='1929-22-22')
education = models.CharField(max_length=50, blank=True)
country_living = models.CharField(max_length=50, choices=LIVING_COUNTRIES, default='UNITEDSTATESOFAMERICA', blank=True)
created_at = models.DateTimeField(auto_now_add=True, blank=True)
password = models.CharField(max_length=30, null=True)
Now I want to display country_living field in my html form.
I have tried like this:
<select name="category" id="id_category">
{% for category in living_countries.country_living %}
<option value="{{ category.country_living }}">{{ category.country_living }</option>
{% endfor %}
</select>
def get(self, request):
context = {}
living_countries = models.Employee.objects.all()
context['living_countries'] = living_countries
return render(request, 'authentication/employee_register.html', context)
But it doesn't work. Does anyone know how to access and display this field?
LIVING_COUNTRIES is a list in your models.py file but it is outside the Employee model, so there's no way for it to show up inside your view and from your view to your template.
to resolve that in your views, you can do from from .models import *
this way the model and list will be available to us.
Better way of working would be to have a model for LivingCountries and use that as one-to-one relationship with Employee model.
Next, in views, you need to correct the query from models.Employee.objects.all() to Employee.objects.all()
the view function can be simplified as following and the list should be passed within the function as following
def get(request):
employees = Employee.objects.all()
living_countries_list = LIVING_COUNTRIES
return render(request, 'authentication/employee_register.html', {
'employees': employees,
'living_countries_list': living_countries_list
})
since now you have employee data and living countries list being sent to template, you can do following to get list of countries
in your template
<select name="category" id="id_category">
{% for each in living_countries_list %}
<option value="{{ each.0 }}">{{ each.1 }</option>
{% endfor %}
</select>

How do I use a for loop to reuse a django form in a template

After struggling with this issue for a while, I am hoping someone here can point me in a more productive direction.
I am trying to take an indeterminate number of variables in a database (obtained through a different template) and render them on a webpage, each variable with a simple data entry form, to be saved back to the database. Basically, it's a tracker for analysis. Say I want to track my daily sleep, running time, and calorie intake (the variables). I have those saved in a database as variables and want to call upon those variables and show them on a webpage with a daily entry form. I am using a "for" loop right now and it renders the way I want it to, with the variable name and the form, but it is only saving the last item in the variable list. How do I amend the code below such that when I hit the save button for each form rendeded, it saves the information for that variable (not just the last one rendered).
Below is the code. Any and all help would be infinitely appreciated.
Models...
class Variable(models.Model):
date_added = models.DateTimeField(auto_now_add=True)
created_by = models.ForeignKey(get_user_model(), default='', on_delete=models.CASCADE) # id the active user
ENTRY_TYPE_CHOICES = [
('numeric', 'enter a daily number'),
('scale', 'rate daily on a scale of 1-10'),
('binary', "enter daily, 'yes' or 'no' "),
]
variable = models.CharField(max_length=50, default='')
entry_type = models.CharField(max_length=50, choices=ENTRY_TYPE_CHOICES, default="numeric")
def __str__(self):
return self.variable
class DailyEntry(models.Model):
date = models.DateField(default=datetime.date.today)
# date_added = models.DateTimeField(auto_now_add=True)
created_by = models.ForeignKey(get_user_model(), default='', on_delete=models.CASCADE) # id the active user
variable_name = models.CharField(max_length=50, default='')
variable_id = models.SmallIntegerField(default=0000)
entry = models.FloatField(default=9999)
class Meta:
verbose_name_plural = 'Daily Entries'
def __str__(self):
return self.variable
Form...
class VariablesForm(forms.ModelForm):
class Meta:
model = Variable
fields = ['variable', 'entry_type' ]
labels = {'variable':'Dependent variable to track', 'entry_type': 'Type of measure'}
class DailyEntryForm(forms.ModelForm):
class Meta:
model = DailyEntry
fields = ['variable_name', 'variable_id', 'entry', 'date']
labels = {'entry': 'Daily entry', 'date': 'Date'}
widgets = {'variable_name': forms.HiddenInput(), 'variable_id': forms.HiddenInput()}
Views...
def daily_entry(request):
''' page to make daily entries '''
vars = Variable.objects.filter(id__gt = 0 )
if request.method != 'POST':
# No data submitted. GET submitted. Create a blank form
form = DailyEntryForm()
else:
#POST data submitted. Process data
form = DailyEntryForm(data=request.POST)
if form.is_valid():
data = form.save(commit=False)
data.created_by = request.user
data.save()
return HttpResponseRedirect(reverse('entry_new'))
context = {'form': form, 'vars': vars}
return render(request, 'entry_new.html', context)
and HTML...
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
{% for var in vars %}
<div>
<ul>
<h3>{{ var.variable }}</h3>
<form class="" action="" method="post">
{% csrf_token %}
{{ form|crispy }}
<input type="hidden" name="variable_id" value="{{ var.id }}" >
<input type="hidden" name="variable_name" value="{{ var.variable }}">
<input type="submit" name="" value="Save" />
</ul>
</div>
{% endfor %}
{% endblock content %}
Any help, well, helps...
Thanks!

Django How to Post comment on only one List item

I am trying to create django commerce app I am little bit stuck on a thing
When I post comment via form I created
<form action="{% url 'comment' list_id.id %}" method="POST">
{% csrf_token %}
<textarea name="comment" class="inp-cmt" rows="3"></textarea>
<input type="submit">
</form>
the comment is posted but it post on all of my list page I wanted only on the page where comment is posted
my comment section
{% if allcomments %}
<h1>Comments</h1>
<div class="card-cmt">
{%for com in allcomments%}
<li style="list-style: none;">
<footer class="post-info">
<span>{{com.user}}</span>
<p>{{com.text}}</p>
</footer>
</li>
{% endfor %}
</div>
{% endif %}
my urls
urlpatterns = [
path("", views.index, name="index"),
path("login", views.login_view, name="login"),
path("logout", views.logout_view, name="logout"),
path("register", views.register, name="register"),
path("newlist", views.create_listing, name="new_list"),
path("item", views.add_item, name="new_item"),
path("listing/<int:list_id>", views.listing, name="listing"),
path("delete/<int:item_id>", views.delete_list, name="delete"),
path("comment/<int:list_id>", views.comments, name="comment")
]
my views for comment and listing
def comments(request, list_id):
coms = Comments()
if request.method == 'POST':
coms.user = request.user.username
coms.text = request.POST.get('comment')
coms.listid = list_id
coms.save()
return redirect('listing', list_id)
else :
return redirect('index')
def listing(request, list_id):
list_item = Listing.objects.get(id=list_id)
return render(request, "auctions/listing.html",{
"list_id" : list_item,
"allcomments" : Comments.objects.all()
})
models
class Listing(models.Model):
owner = models.CharField(max_length =64,default="N/A")
productname = models.CharField(max_length=100)
price = models.DecimalField(max_digits=10, decimal_places=2)
description = models.CharField(max_length=999, default="test")
date = models.DateField(auto_now_add=True)
link = models.CharField(max_length=200, default="test1")
def __str__(self):
return f"{self.owner} {self.productname} {self.price} {self.date} {self.description} {self.link}"
class Comments(models.Model):
user = models.CharField(max_length=64)
text = models.TextField()
date = models.DateTimeField(auto_now_add=True)
listid = models.IntegerField(default=0)
def __str__(self):
return f"{self.user} {self.text} {self.date} {self.listid}"
You're returning all comments on every listing when you do "allcomments" : Comments.objects.all()
The problem is in your listing function. Try this instead:
def listing(request, list_id):
list_item = Listing.objects.get(id=list_id)
return render(request, "auctions/listing.html",{
"list_id" : list_item,
"allcomments" : Comments.objects.filter(listid=list_id)
})
Notice the change - from "allcomments" : Comments.objects.all() to "allcomments" : Comments.objects.filter(listid=list_id)
Also, your implementation for class Comments and class Listing could be a bit better. Have you ever come across something called a ForeignKey? It will be a lot more efficient to use that. https://docs.djangoproject.com/en/3.1/ref/models/fields/#django.db.models.ForeignKey

Django - Filter Model Objects (Posts) Using Form

So I have a model called Blog
class Blog(models.Model):
tagoptions = (
(u'Project', u'Project'),
(u'IT', u'IT'),
(u'Robotics', u'Robotics'),
. . .
(u'-', u'-'),
)
user = models.TextField(blank=True, null=True)
title = models.CharField(max_length=50, default='')
context = models.TextField(max_length=5000, default='')
ireceived = models.IntegerField(default=0, blank=True, null=True)
personnelneeded = models.IntegerField(default=1)
datewritten = models.DateField(default=datetime.date.today, blank=True, null=True)
tags = models.CharField(max_length=100, choices=tagoptions, default='-')
def __str__(self):
return str(self.user) + ": id" + str(self.id) + " - title: " + str(self.title)
and a form for filtering the objects using "tags"
class FilterOption(forms.Form):
tagoptions = (
(u'showall', u'Show All'),
(u'Project', u'Project'),
(u'IT', u'IT'),
. . .
(u'-', u'-'),
)
tags = forms.ChoiceField(choices=tagoptions, initial="showall")
tags.widget.attrs.update({'style' : 'color: black;'})
This is the part of the form for filtering in my template.
<form method="post" action="{% url 'posts' %}">
{% csrf_token %}
<p>{{ form.tags }} <input type="submit" name="filter" value="Filter"/></p>
</form>
Here is what I use in my template to display the top 10 most recent posts.
{% for p in postshow|slice:":10" %}
<br><br>
<div class="postdisplay">
<h1><a class="stuffurl" href="{% url 'posted' postid=p.id %}"><u>{{ p.title }}</u></a></h1>
<h4>Post by <a class="stuffurl" href="{% url 'user' user_login_name=p.user %}"><u>{{ p.user }}</u></a>, {{ p.datewritten}}</h4>
<h4>Tag: {{ p.tags }}
</div>
<br><br>
{% endfor %}
Then finally in my views I have
def posts(request):
postshow = Blog.objects.order_by('-id')
if request.method == 'POST':
form = FilterOption()
if form.is_valid():
filteropt = form.cleaned_data['tags']
if filteropt != showall:
postshow = Blog.objects.order_by('-id')
else:
postshow = Blog.objects.filter(tags=filteropt).order_by('-id')
else:
form = FilterOption()
context = {'postshow' : postshow, 'form' : form}
return render(request, 'home/posts.html', context)
When ever I submit the form, it's supposed to check if the input says show all or not. If it does then it does not filter anything and if not it filters the objects so that only the objects with the tag of the input gets shown. However, the code seems to be stuck at form.is_valid (I checked using print). Another possible problem is that even if it worked pass form.is_valid, the filter won't work since the input is refreshed whenever you submit the form.
It will be greatly appreciated if someone can help me fix my code so that I can select a tag and the post will be filtered and if I select "show all", it shows all posts without filtering them.
Before checking if the form is valid, try passing the request.POST data into it:
form = FilterOption(request.POST)

How to treat CMS fields that support HTML [Django]

I have a Django site with a Post object like so:
class Post(models.Model):
title = models.CharField(max_length=100,blank=True,null=True)
body = models.TextField(blank=True,null=True)
author = models.ForeignKey(User,blank=True,null=True)
date_created = models.DateTimeField(default=timezone.now)
date_updated = models.DateTimeField(auto_now_add=True)
image = models.ImageField(upload_to=post_dir, blank=True, null=True)
def __unicode__(self):
return unicode(self.date_created.strftime('%Y-%m-%d %H:%M') + ' ' + self.title)
which outputs body TextField like so in order to support HTML:
{% if post.body %}
<p>
{{ post.body | safe }}
</p>
{% endif %}
My question is, since the admins can input HTML which could potentially malform the html (such as post.body = '</div></div>'), what is the best way to format and sanitize this textfield while still allowing users to input html?
I got the desired functionality with some extras using django-ckeditor