How to display different custom users after logging in Django - python

I have 2 custom users, student and teacher. I want that if student is logged in, a particular message is displayed, otherwise if teacher is logged in, another message to show.
{% if request.user.is_authenticated %}
{% if user is student %}
<p>Welcome, {{ user.student.surname }} Thanks for logging in.</p>
{% else %}
{% if user is teacher%}
<p>Welcome, {{ user.teacher.surname }} Thanks for logging in.</p>
{% endif %}
{% endif %}
class User(AbstractUser):
pass
class Student(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
name = models.CharField(max_length=30, null=True, blank=True, default=None)
surname = models.CharField(max_length=50, null=True, blank=True, default=None)
class Teacher(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
name = models.CharField(max_length=30, null=True, blank=True, default=None)
surname = models.CharField(max_length=50, null=True, blank=True, default=None)
email = models.EmailField(unique=True, null=True, blank=True, default=None)
User.student = property(lambda p: Student.objects.get_or_create(user=p)[0])
User.teacher = property(lambda p: Teacher.objects.get_or_create(user=p)[0])

First, I believe it's not a really good idea to have user.teacher and user.student as a property for two reasons:
1. I assume that a user can be either a student or a teacher, but not both (please correct me if I'm mistaken). You are using get_or_create, so, for instance, if you'll try to access a user teacher property with user being already a student, you will end up in the situation when the user is both a student and a teacher.
2. Django ORM already does this for you: using OneToOneField you can reference Teacher or Student object from your User object as user.teacher or user.student as long as the corresponding User or Teacher exists.
You can use hasattr to check if the given user is a teacher or a student:
class User(AbstractUser):
#property
def is_teacher(self):
return hasattr(self, 'teacher')
#property
def is_student(self):
return hasattr(self, 'student')
Then render your template accordingly:
{% if user.is_teacher %}
# Do teacher-related logic
{% elif user.is_student %}
# Do student-related logic
{% else %}
# This should not be the case, but you may want to display an error message or something
{% endif %}

Related

How to Create Buttons for not Null fields only in Django?

I'm fairly new to Django and couldn't find a way to do this yet. I have a model like this:
class Profile(models.Model):
user = models.OneToOneField("User", on_delete=models.SET_NULL, null=True)
user_name = models.CharField(max_length=50)
linkedin = models.URLField(max_length=254, null=True, blank=True)
instagram = models.URLField(max_length=254, null=True, blank=True)
spotify = models.URLField(max_length=254, null=True, blank=True)
On my HTML, I have buttons for each social media field, but I don't want to show them if they are null. How can I create a for loop that will loop through the social media fields only and create buttons for only not null fields?
If your links aren't in a for loop in your HTML. I suggest you to use if block for every social media link.
example is:
{% if profile.linkedin %}
LinkedIn
{% if profile.spotify %}
Spotify
{% else %}
{% endif %}

Custom User PK (Primary Key) - Django - Python

I built a website with Python Django and part of it displays lines of already input data with the primary key next to it. Now I have separate user data by using a foreign key field in each one of my models and the specific user's data is only shown to that logged in user except that all the data regardless of the user is saved in one spot with the model shown in the admin interface(because I'm using foreign keys to separate data). My problem is that I need to display the primary key of just the logged-in user. Take this, for example, if User1 adds 1 line of data to their page then User2 adds 1 line of data on their page which will appear separate from one another, then User1 uploads another line of data, Then I user traditional primary key to number the data lines of User1 the numbers will be 1 and three instead of keeping them in numerical order of 1 and 2 and disregarding User2's data in the counting of the data. It's as if I need a separate primary key for each user. Sorry this is really hard to explain. I have found a temporary solution of using {{ forloop.revcounter }} to count in a for loop instead of using the primary key but the problem with this is that when data is deleted all the numbers above it go down one because this tag just counts how many times the for loop has looped. I have found no information of the internet about this and how to solve it beyond this. I might just be looking in the wrong places but I need help. Thanks!
EDIT:
models.py
class Sheet_Extinguisher(models.Model):
user = models.ForeignKey(User, default=True, related_name="Extinguisher", on_delete=models.PROTECT)
floor = models.CharField(max_length=5, choices=FLOOR_LEVEL_FE, blank=True, null=True, verbose_name='Floor / Level')
area_room = models.CharField(max_length=35, blank=True, null=True, verbose_name='Area / Room')
building_address = models.CharField(max_length=46, choices=BUILDING_ADDRESS, blank=True, null=True, verbose_name='Building and Address')
type = MultiSelectField(choices=TYPE_FE, blank=True, null=True, verbose_name='Type')
size = models.CharField(max_length=3, choices=SIZE_FE, blank=True, null=True, verbose_name='Size')
hydrostatic_date = models.DateField(blank=True, null=True, verbose_name='Last Hydrostatic Test')
mass_notes = models.CharField(max_length=20, blank=True, null=True, verbose_name='Mass Fire Tech Notes')
notes = models.TextField(max_length=500, blank=True, null=True, verbose_name="Inspector's note")
class Meta:
ordering = ['building_address']
def __str__(self):
return self.building_address or 'None'
def get_absolute_url(self):
return reverse('list_extinguisher')
HTML (with pk):
{% if filter.qs %}
{% for post in filter.qs %}
<tr>
<td><div class="item1" style="text-align: center;">{{ post.pk }}</div></td>
{% endfor %}
{% endif %}
HTML (just with forloop counter):
{% if filter.qs %}
{% for post in filter.qs %}
<tr>
<td><div class="item1" style="text-align: center;">{{ forloop.revcounter }}</div></td>
{% endfor %}
{% endif %}

django admin data does not register in database

I am building an ecommerce website with Django and having some difficulties to transfer data from the admin page to the database and then html. I am new to Django and I would love your help.
I added 7 "products" (class Product) via Django admin page.
models.py
from django.db import models
from django.contrib.auth.models import User
class Customer(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True)
name = models.CharField(max_length=200, null=True)
email = models.CharField(max_length=200, null=True)
def __str__(self):
return self.name
class Product(models.Model):
name = models.CharField(max_length=200)
price = models.FloatField()
def __str__(self):
return self.name
class Order(models.Model):
customer = models.ForeignKey(Customer, on_delete=models.SET_NULL, null=True, blank=True)
date_ordered = models.DateTimeField(auto_now_add=True)
complete = models.BooleanField(default=False)
transaction_id = models.CharField(max_length=100, null=True)
def __str__(self):
return str(self.id)
class OrderItem(models.Model):
product = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True)
order = models.ForeignKey(Order, on_delete=models.SET_NULL, null=True)
quantity = models.IntegerField(default=0, null=True, blank=True)
date_added = models.DateTimeField(auto_now_add=True)
class ShippingAddress(models.Model):
customer = models.ForeignKey(Customer, on_delete=models.SET_NULL, null=True)
order = models.ForeignKey(Order, on_delete=models.SET_NULL, null=True)
address = models.CharField(max_length=200, null=False)
city = models.CharField(max_length=100, null=False)
country = models.CharField(max_length=100, null=False)
postcode = models.CharField(max_length=100, null=False)
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.address
views.py
from django.shortcuts import render
from .models import *
def products(request):
products = Product.objects.all()
context = {'products':products}
return render(request, 'store/products.html')
def cart(request):
context = {}
return render(request, 'store/cart.html')
def checkout(request):
context = {}
return render(request, 'store/checkout.html')
def home(request):
context = {}
return render(request, 'store/home.html')
admin.py
from django.contrib import admin
from .models import *
admin.site.register(Customer)
admin.site.register(Product)
admin.site.register(Order)
admin.site.register(OrderItem)
admin.site.register(ShippingAddress)
In settings.py, the default database is sqlite3
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
Screen shot of Django admin page with products successfully added
I have done the migrations and the database db.sqlite3 exits in my project folder.
However, when I check the values of the table "store_product", it seems empty...
prompt
SQLite version 3.33.0 2020-08-14 13:23:32
Enter ".help" for usage hints.
sqlite> .width
sqlite> .mode markdown
sqlite> select * from store_product
...>
In my html page where I want to display the products, nothing displays ... The variable products is empty :
products.html
{% if products is defined %}
value of variable: {{ products }}
{% else %}
variable is not defined
{% endif %}
it displays nothing ...
Thanks a lot for your help.
You never pass the context to your view. It should be like:
def products(request):
products = Product.objects.all()
context = {'products':products}
return render(request, 'store/products.html', context)
Also that {% if products is defined %} would not make any sense. So simply render the products:
{% for product in products %}
Product: {{ product.name }}
Price: {{ product.price }}
{% empty %}
No products to display!
{% endfor %}
Your template code looks wrong - is defined is not python.
The following is sufficient:
{% if products %}
<ul>
{% for product in products %}
<li>{{ product.name }}: {{ product.price }}
{% endfor %}
</ul>
{% else %}
No products.
{% endif %}
The Django Admin shows exactly whatever is in its connected database, there is no cache.
If you cannot see the data in the sqlite client or your other view, this makes me suspect that you are not using the same database or that the sqlite lost the data in the meanwhile (deleting the file will recreate it the next time you start your local server, and the data will be lost).
You might want to start using the DB you are planning to use in production, to rule these issues out, and to be closer to your production setup when developing.

How to create a form field for every foreignkey in manytomany relationship in Django

I don't understand how to build a specific form in Django.
First of all here are my models:
class Category(models.Model):
name = models.CharField(max_length=200, unique=True)
class Assessment(models.Model):
name = models.CharField(max_length=200)
pub_date = models.DateTimeField(verbose_name=_('date published'), default=timezone.now)
classgroup = models.ForeignKey(ClassGroup, verbose_name=_('class'), on_delete=models.CASCADE, related_name='+')
category = models.ManyToManyField(Category, through='AssessmentScale', through_fields=('assessment', 'category'),)
total = models.IntegerField()
class AssessmentScale(models.Model):
assessment = models.ForeignKey(Assessment, on_delete=models.CASCADE)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
value = models.IntegerField()
I would like to have a form like this html form. Actually, an assessment scale is sub-divided into different categories. So when I create an assessment, I'd like have a form field for each category allowing to add a value via my custom intermediary model AssessmentScale. But I really don't know the Django way to build this form. I read this post, which is similar I think, and someone advised the use of Inline model formsets. But I don't understand how to solve my problem with the latter. Could you help me?
I had no answer from Stackoverflow but a friend of mine solved my problem like this with inline formset:
# forms.py
class AssessmentForm(ModelForm):
class Meta:
model = Assessment
exclude = ('category',)
CategoryAssessmentFormSet = inlineformset_factory(
Assessment,
Assessment.category.through,
fields=['category', 'value'],
can_delete=False,
extra=Category.objects.count(),
max_num=Category.objects.count(),
widgets={'category': Select(attrs={'hidden': 'true'})}
)
in my view, to render the formset:
# views.py
initial = [{'category': category} for category in Category.objects.all()]
formset = CategoryAssessmentFormSet(initial=initial)
Select is hidden but I still want the name of the selected field, in my template:
# template
{{ formset.management_form }}
{% for form in formset %}
<div class="p-2">
{% for value,selected in form.fields.category.choices %}
{% if value == form.category.value %}{{ selected }}{% endif %}
{% endfor %}
{{ form.category }}
</div>
<div>
{{ form.value}}
</div>
{% endfor %}

Bringing Information from django.contrib.auth.models.User into View

I have the following model in my Django project:
from django.contrib.auth.models import User
class Project(models.Model):
project_title = models.CharField(max_length=200)
project_description = models.CharField(max_length=200, default="")
created_date = models.DateTimeField('date created')
owner = models.ForeignKey(User)
def __str__(self):
return self.project_title
This view uses the Project model as follows:
class ProjectView(generic.edit.UpdateView):
model = Project
fields = ['project_title','project_description']
template_name = 'steps/project.html'
success_url = reverse_lazy('steps:index')
My question is how can I bring the User's fields into my ProjectView so I can then use them in templates? In particular, I would like to display the logged-in user's name and email.
user information placed on request, not on views. So you can write in template {{user.username}}, or {{user.email}}. and you'll get it. Of course if user.is_authenticated
in your template write:
{% if request.user.is_authenticated %}
{{ request.user.username }}
{{ request.user.email }}
{% endif %}

Categories

Resources