Check if User is in Many2Many field - django

I have the following model with a m2m field where logged in Users can show interest in a publication:
models.py
from django.db import models
class Publication:
title = models.CharField(max_lenth=512)
users_interested = models.ManyToManyField(User)
views.py
from django.shortcuts import render
from django.views import View
from .models import Publication
class listPublicationView(View):
def get(self, request, *args, **kwargs):
publications = Publication.objects.all()
return render(request, "base.html", {'publications': publications})
Now i try to produce a "i am already interested" in the template when a logged in user is already interested in the publication:
base.html
{% for publication in publications %}
{{publication.title}}
{% if currently logged in User is interested in publication (check users_interested) %}
i am already interested
{% endif %}
{% endfor %}
I think about something like this:
{% if user.id in publication.users_interested__id %}

Try like this:
{% if request.user in publication.users_interested.all %}
request.user property holds the current logged in user
Then you use the in operator with publications.users_interested.all() (Note that there are no parenthesis on .all() in template

This seems to look like a good solution:
models.py
from django.db import models
class Publication:
title = models.CharField(max_lenth=512)
#added a reverse accessor
users_interested = models.ManyToManyField(User, related_name='users_interested')
view.py
from django.shortcuts import render
from django.views import View
from .models import Publication
class listPublicationView(View):
def get(self, request, *args, **kwargs):
publications = Publication.objects.all()
# create a set of group IDs that this user is a part of
current_user = request.user
user_publication_set = set(current_user.users_interested.values_list('id', flat=True))
#pass set to template
return render(request, "base.html", {'publications': publications, 'user_publication_set': user_publication_set})
base.html
{% for publication in publications %}
{{publication.title}}
{% if publication.id in user_publication_set %}
i am already interested
{% endif %}
{% endfor %}
Found this solution in Django: check for value in ManyToMany field in template

Related

I want to make it so that each product will have a link, and the link will link to a page with the product's info

I am working on a django project.
Here is my models.py file:
class Product(request):
name = models.CharField(max_length=255)
cost = models.FloatField(max_length=255)
info = models.CharField(max_length=2000)
Here is my views.py file:
from django.shortcuts import render
from django.http import HttpResponse
from .models import Product
def index(request):
products = Product.objects.all()
return render(request, 'index.html',
{'products': products})
# I know the below is incorrect, but I don't know how to correct it.
def information(request):
info = Product.objects.all()
return HttpResponse(info[products.index(product)].info)
Here is my index.html file:
{% for product in products %}
<l1>{{product.name}} ${{ product.price }}</li>
{% endfor %}
I want to make it so that each product will have a link, and the link will link to a page with the product's info. How can I dynamically do this?
Thanks.
My suggestion would be to use django's built-in generic views, they are very useful.
So first, you need a ListView to list all your products, for example:
from django.views import generic
class ProductList(generic.ListView):
model = models.Product
template_name = 'products/product_list.html'
context_object_name = 'product_list'
And then a DetailView:
class ProductDetail(generic.DetailView):
model = models.Product
template_name = 'products/product_detail.html'
context_object_name = 'product'
Now in your list template you can do as follows:
{% if product_list %}
{% for product in product_list %}
{{product.name}}
{% endfor %}
{% endif %}
And on your detail template you can do something similar to show for example the cost and the info. Obviously this is just an example, and you would have to change it to suit your needs. But this should help you get started. For more information, you can also refer to the documentation on this:
https://docs.djangoproject.com/en/3.0/ref/class-based-views/generic-display/

Fetch complete user record in DJango

Below is the user record present in MySQL Database table - auth_user
Please click the image if it is not clear here
Below is my code present in View.py file.
from django.contrib.auth.models import User
from django.http import HttpResponse
from django.views import View
class loginController(View):
def get(self, request):
userobj = User.objects.filter(username = 'username')
return HttpResponse(request.POST.get('username'));
It returns just the username. Can you please suggest that why it just fetch the username and not the complete record?
Please let me know if you need more info
It returns the list of user objects represented by username. You can access all the properties of object as (obj.property). eg: if you have first_name in your user model
u = userobj.first()
u.first_name
u.last_name
If you want to fetch the complete user information, then you have to return User object, so that you can iterate throught that User object in your template
Example:-
Views.py
from django.views import generic
class loginController(generic.ListView):
template_name = 'project_app/user-list.html'
model = User
def get_queryset(self):
userlist = User.objects.all()
return userlist
project_app/user-list.html
{% if object_list %}
{% for user in object_list %}
<p>{{ user.username }}</p>
<p>{{ user.first_name }}</p>
{% endfor %}
{% endif %}

Display data from a database in a HTML page using django views

I have a problem with creating a view with data from the database. I created a view that should download data from videos (var films) and display them, unstable
views.py
from .models import Films
def index(request):
filmy = Films.objects
return render(request, 'films/index.html',{'filmy':filmy})
index.html
<h1>Films</h1>
{% for film in films.all %}
{{filmy.summary}}
<br>
{% endfor %}
models.py
class Films(models.Model):
image = models.ImageField(upload_to='images/')
summary = models.CharField(max_length=200)
def __str__(self):
return self.summary
I only have a blank page.
Your views.py
from django.shortcuts import render
from django.http import HttpResponse
from .models import Films
# Create your views here.
def index(request):
films = Films.objects.all()
return render(request, 'films/index.html',{'films':films})
In index.html
{% for film in films %}
<p> {{film.summary}} </p>
{% endfor %}
I hope that helps.

Displaying a series of inline forms for a queryset of Django models

If I have models like this:
from django.db import models
class Publisher(models.Model):
name = models.CharField(max_length=255)
class Book(models.Model):
publisher = models.ForeignKey('Publisher')
title = models.CharField(max_length=255)
class BookImage(models.Model):
book = models.ForeignKey('Book')
file = models.ImageField(max_length=255)
title = models.CharField(max_length=255)
I want to make a page that:
Lists all the Books for a particular publisher (e.g. Book.objects.filter(publisher=34)).
For each Book, displays any existing BookImages.
For each Book displays 3 forms for uploading and titling new BookImages.
One submit button.
I don't need to edit the details of the Books - the forms are only for BookImages.
I'm getting in a tangle with modelformset_factory and inlineformset_factory and none of it is right... I feel like I'm making things too complicated. Any ideas?
Update:
Here are some things I've tried that head in a sort-of-right direction, but I'm not sure they help:
# Forms for multiple Books for this Publisher
# But I don't think I need forms for the Books in my situation?
my_publisher = Publisher.objects.get(pk=37)
BookFormSet = modelformset_factory(Book, fields=(['title']))
formset = BookFormSet(queryset=Book.objects.filter(publisher=my_publisher))
# Multiple BookImages on one Book:
# Good, but how do I do this for all of a Publisher's Books, and display existing BookImages?
my_book = Book.objects.get(pk=42)
BookImageFormSet = inlineformset_factory(Book, BookImage, fields=('file', 'title'))
formset = BookImageFormSet(instance=my_book)
I found an example of how to do this in this blog post. Below I've rewritten the example using my Publisher/Book/BookImage models, and generic class-based views, for future reference.
The form also allows the user to edit the titles of the Books, which wasn't what I originally wanted, but this seems easier than not doing it; the inline Book forms require at least one field each, so we may as well include the Book's title.
Also, to see how this worked, I've put together a small Django project using this code, and a little more detail, available on GitHub.
models.py:
from django.db import models
class Publisher(models.Model):
name = models.CharField(max_length=255)
class Book(models.Model):
title = models.CharField(max_length=255)
publisher = models.ForeignKey('Publisher', on_delete=models.CASCADE)
class BookImage(models.Model):
book = models.ForeignKey('Book', on_delete=models.CASCADE)
image = models.ImageField(max_length=255)
alt_text = models.CharField(max_length=255)
forms.py:
from django.forms.models import BaseInlineFormSet, inlineformset_factory
from .models import Publisher, Book, BookImage
# The formset for editing the BookImages that belong to a Book.
BookImageFormset = inlineformset_factory(
Book,
BookImage,
fields=('image', 'alt_text')),
extra=1)
class BaseBooksWithImagesFormset(BaseInlineFormSet):
"""
The base formset for editing Books belonging to a Publisher, and the
BookImages belonging to those Books.
"""
def add_fields(self, form, index):
super().add_fields(form, index)
# Save the formset for a Book's Images in a custom `nested` property.
form.nested = BookImageFormset(
instance=form.instance,
data=form.data if form.is_bound else None,
files=form.files if form.is_bound else None,
prefix='bookimage-%s-%s' % (
form.prefix,
BookImageFormset.get_default_prefix()),
)
def is_valid(self):
"Also validate the `nested` formsets."
result = super().is_valid()
if self.is_bound:
for form in self.forms:
if hasattr(form, 'nested'):
result = result and form.nested.is_valid()
return result
def save(self, commit=True):
"Also save the `nested` formsets."
result = super().save(commit=commit)
for form in self.forms:
if hasattr(form, 'nested'):
if not self._should_delete_form(form):
form.nested.save(commit=commit)
return result
# This is the formset for the Books belonging to a Publisher and the
# BookImages belonging to those Books.
PublisherBooksWithImagesFormset = inlineformset_factory(
Publisher,
Book,
formset=BaseBooksWithImagesFormset,
fields=('title',),
extra=1)
views.py:
from django.http import HttpResponseRedirect
from django.views.generic import FormView
from django.views.generic.detail import SingleObjectMixin
from .forms import PublisherBooksWithImagesFormset
from .models import Publisher, Book, BookImage
class PublisherUpdateView(SingleObjectMixin, FormView):
model = Publisher
success_url = 'publishers/updated/'
template_name = 'publisher_update.html'
def get(self, request, *args, **kwargs):
# The Publisher whose Books we're editing:
self.object = self.get_object(queryset=Publisher.objects.all())
return super().get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
# The Publisher whose Books we're editing:
self.object = self.get_object(queryset=Publisher.objects.all())
return super().post(request, *args, **kwargs)
def get_form(self, form_class=None):
"Use our formset of formsets, and pass in the Publisher object."
return PublisherBooksWithImagesFormset(
**self.get_form_kwargs(), instance=self.object)
def form_valid(self, form):
form.save()
return HttpResponseRedirect(self.get_success_url())
templates/publisher_update.html:
{% extends 'base.html' %}
{% block content %}
<form action="" method="post" enctype="multipart/form-data">
{% for hidden_field in form.hidden_fields %}
{{ hidden_field.errors }}
{{ hidden_field }}
{% endfor %}
{% csrf_token %}
{{ form.management_form }}
{{ form.non_form_errors }}
{% for book_form in form.forms %}
{# Output a Book form. #}
{% for hidden_field in book_form.hidden_fields %}
{{ hidden_field.errors }}
{% endfor %}
<table>
{{ book_form.as_table }}
</table>
{# Check if our `nested` property exists, with BookImage forms in it. #}
{% if book_form.nested %}
{{ book_form.nested.management_form }}
{{ book_form.nested.non_form_errors }}
{% for bookimage_form in book_form.nested.forms %}
{# Output the BookImage forms for this Book. #}
{% for hidden_field in bookimage_form.hidden_fields %}
{{ hidden_field.errors }}
{% endfor %}
<table>
{{ bookimage_form.as_table }}
</table>
{% endfor %}
{% endif %}
{% endfor %}
<input type="submit" value="Update books">
</form>
{% endblock content %}
All formset_factory methods require a form which they can generate multiple times. So, you need to create a form (since you are using Models, you need to create a model form) for BookImage.
forms.py
class BookImageForm(ModelForm):
class Meta:
model = BookImage
# book field wont be generated in the template if it is excluded
exclude = ['book',]
views.py
from django.forms.formsets import formset_factory
def your_view(request):
# I'm just including the formset code which you need, im assuming you have the remaining code in working condition
# TO HANDLE NORMAL RENDERING OF FORM WHEN USER OPENS THE WEBPAGE
if request.method == "GET":
bookimage_form = BookImageForm()
bookimage_formset = formset_factory(bookimage_form, max_num=3)
return render(request, 'index.html', {'bookimage_formset': bookimage_formset})
# WHEN USER SUBMITS THE FORM
if request.method == "POST"
# Consider BookImageFormSet as a placeholder which will be able to contain the formset which will come through POST
BookImageFormSet = modelformset_factory(BookImage, BookImageForm, max_num=3)
# bookimage_formset is a variable which stores the Formset of the type BookImageFormSet which in turn is populated by the data received from POST
bookimage_formset = BookImageFormSet(request.POST)
# HIDDEN AUTO GENERATED FIELDS ARE CREATED WHEN THE FORMSET IS RENDERED IN A TEMPLATE, THE FOLLOWING VALIDATION CHECKS IF THE VALUE OF THE HIDDEN FIELDS ARE OKAY OR NOT
if bookimage_formset.is_valid():
# EACH FORM HAS TO BE INDIVIDUALLY VALIDATED, THIS IS NORMAL FORM VALIDATION. ONLY DIFFERENCE IS THAT THIS IS INSIDE A FOR LOOP
for bookimage_form in bookimage_formset:
if bookimage_form.is_valid:
bookimage_form.save()
return HttpResponse("Form saved!")
return HttpResponseRedirect('/')
PS: You can get the data from request.POST for other models in the same view to handle other data (such as the data for Books)

Passing group name of a user in context and accessing in template in django

I have used mixins with class-based views in my django app. I also have created a group named Instructors to allow only user belonging to this group to have certain permissions which are to edit, add and delete a course object.
In the ManageCourseList View which is responsible for rendering the courses created by the current user, I tried to override the get_context_data method to pass an additional 'group_list' argument which contains the groups the user belongs to.
I tried to access it in the template ManageCourseList view renders.
The problem is though the current user belongs to Instructors group but still it renders the else condition data.
Please help,My files:
Views.py
from django.shortcuts import render
from django.core.urlresolvers import reverse_lazy
from django.views.generic.list import ListView
from django.views.generic.edit import CreateView,UpdateView,DeleteView
from django.contrib.auth.mixins import LoginRequiredMixin,PermissionRequiredMixin
from .models import Course
class OwnerMixin(object):
def get_queryset(self):
qs = super(OwnerMixin,self).get_queryset()
return qs.filter(owner=self.request.user)
class OwnerEditMixin(object):
def form_valid(self,form):
form.instance.owner = self.request.user
return super(OwnerEditMixin, self).form_valid(form)
class OwnerCourseMixin(OwnerMixin,LoginRequiredMixin):
model = Course
fields = ['subject','title','slug','overview'] # why use this attribute?
success_url = reverse_lazy('courses:manage_course_list') # use of it?
class OwnerCourseEditMixin(OwnerCourseMixin,OwnerEditMixin):
fields = ['subject','title','slug','overview']
success_url = reverse_lazy('courses:manage_course_list')
template_name = 'courses/manage/course/form.html'
class ManageCourseListView(OwnerCourseMixin,ListView):
template_name = 'courses/manage/course/list.html'
def get_context_data(self, **kwargs):
context = super(ManageCourseListView,self).get_context_data(**kwargs)
context['group_list'] = self.request.user.groups.all()
return context
list.html
{% extends "base.html" %}
{% block title %}My courses{% endblock %}
{% block content %}
{% if group_list.0 == "Instructors" %}
<h1>My courses</h1>
<div class="module">
{% for course in object_list %}
<div class="course-info">
<h3>{{ course.title }}</h3>
<p>
Edit
Delete
</p>
</div>
{% empty %}
<p>You haven't created any courses yet.</p>
{% endfor %}
<p>
Create new course
</p>
</div>
{% else %}
<h1>No courses to display</h1>
{% endif %}
{% endblock %}
Firstly, that method is pointless as it is; you can simply access user.groups in the template.
Secondly, each item in group is a Group object, not a string. So your condition will never succeed; you would need to compare against group.name. Also, it's far from certain that instructors will be the first group.
To solve this, I would rewrite your get_context_data to add an instructors flag rather than the group list:
def get_context_data(self, **kwargs):
context = super(ManageCourseListView,self).get_context_data(**kwargs)
context['user_is_instructor'] = self.request.user.groups.filter(name='Instructors').exists()
return context
and now in the template:
{% if user_is_instructor %}