Custom User PK (Primary Key) - Django - Python - 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 %}

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 %}

Django Prefetch Related Issue - Understand it correctly

I do have the following Issue - I want to display all of the bundles with their component relations in a template:
Here is my ORM-Model:
class Component(models.Model):
plenty_var_number = models.CharField(max_length=120, default=None, unique=True, null=True)
plenty_var_id = models.CharField(max_length=120, default=None, unique=True)
description = models.TextField(max_length=1000)
category = models.ForeignKey(Category, on_delete=models.DO_NOTHING, null=False)
updated_at = models.DateTimeField(auto_now=True, null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True, null=True, blank=True)
def __str__(self):
return f"{self.category.name} - {self.plenty_var_number}"
class Bundle(models.Model):
active = models.BooleanField(default=True)
plenty_var_number = models.CharField(max_length=120, default=None, unique=True, null=True)
plenty_var_id = models.CharField(max_length=120, null=True, default=None)
car = models.ForeignKey(Car, on_delete=models.DO_NOTHING)
# m2m defined by BundleComponentRelation
components = models.ManyToManyField(Component, through="BundleComponentRelation")
linked_to_plenty = models.BooleanField(default=False)
price = models.DecimalField(max_digits=10, decimal_places=2, default=-1.00)
updated_at = models.DateTimeField(auto_now=True, null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True, null=True, blank=True)
class BundleComponentRelation(models.Model):
component = models.ForeignKey(Component, on_delete=models.DO_NOTHING)
bundle = models.ForeignKey(Bundle, on_delete=models.DO_NOTHING)
qty = models.IntegerField(default=1)
updated_at = models.DateTimeField(auto_now=True, null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True, null=True, blank=True)
I have played around with select_related and prefetch_related in my view to pass them via context to the template to display it for my users:
html-template:
{% for bundle in bundles %}
<tr>
<td><p class="fw-bold">{{ bundle.plenty_var_number }}</p></td>
<td>{{ bundle.price }}</td>
<td><p class="fw-bolder mb-0">{{ bundle.car }}</p>
<p class="mb-0">{{ bundle.car.roof_type }}</p>
<p class="mb-0">BJ: {{ bundle.car.production_start }}
- {{ bundle.car.production_end }}</p>
</td>
{# Bundle Component Relations here #}
<td style="font-size: 1em;">
<a href={% url "edit_bundle" bundle.pk %}><i
class="fas fa-xl fa-edit "></i></a>
<a href={% url "sync_bundle" bundle.pk %}><i
class="fas fa-xl fa-sync "></i></a>
</td>
</tr>
{% endfor %}
views.py
def bundle_view(request):
bundles = Bundle.objects.prefetch_related('components').all()
print(bundles[0].components)
return render(request, "all_bundles.html", context={"bundles": bundles})
The output of print(bundles[0].components) is bundle.Component.None
I understood the forward usage of select_related but I do have trouble understanding the reverse thinking of the prefetch_related in my situation.
I think my problem is the lookup syntax of prefetch_related, but I might be wrong here.
What am I missing here?
Thanks in advance.
EDIT
I tried:
{% for bundle in bundles %}
<tr>
<td><p class="fw-bold">{{ bundle.plenty_var_number }}</p></td>
<td>{{ bundle.price }}</td>
<td><p class="fw-bolder mb-0">{{ bundle.car }}</p>
<p class="mb-0">{{ bundle.car.roof_type }}</p>
<p class="mb-0">BJ: {{ bundle.car.production_start }}
- {{ bundle.car.production_end }}</p>
</td>
{% for comp_rel in bundle.components.all %}
{{ comp_rel }}
{% endfor %}
<td style="font-size: 1em;">
<a href={% url "edit_bundle" bundle.pk %}><i
class="fas fa-xl fa-edit "></i></a>
<a href={% url "sync_bundle" bundle.pk %}><i
class="fas fa-xl fa-sync "></i></a>
</td>
</tr>
{% endfor %}
I wanted to get only the related components to the currently iterated bundle. The problem I get here is that the template triggers the database again:
monitoring
Simply using the bundle.component in the template led to
ManyRelatedManager object is not iterable TypError
The reason this happens is because the __str__ of the Component accesses the Category, hence for each {{ comp_rel }}, you render, it will make an extra query.
You should use a Prefetch object [Django-doc] to fetch the Categorys in the same query as the one where you fetch the Components:
from app_name.models import Bundle, Component
from django.db.models import Prefetch
def bundle_view(request):
bundles = Bundle.objects.prefetch_related(
Prefetch('components', Component.objects.select_related('category'))
)
return render(request, 'all_bundles.html', {'bundles': bundles})
There is no problem with your prefetch_related, but the way you want to access these objects, you should do bundles[0].components.all() because objects fetched with reverse relation can be accessed same way as M2M fields
Are you sure it must be prefetch_related? I think it must be select_related.
I think you should use Bundle.objects.select_related('components').all() and Component.objects.prefetch_related('bundle_set').all() with your models. But I'm not sure.
And what about template error - you shoud use {% for component in bundle.components.all %} in template.
And there same problem, mb will helpfull.

How can i make good models for categories in django?

im trying to make an online menu. i want to make a category, sub category and items that goes in one of those.
I mean, an item can be on a category like "sushi" -> nameofsushi, or be in a sub category like sushi -> avocado rolls -> nameofsushi.
i have something like this in my models.py but is there a better way to do it?
class Category(models.Model):
name = models.CharField(max_length=200)
description = models.TextField(max_length=500, verbose_name='Descripción', blank=True, null=True)
parent = models.ForeignKey('self', related_name='children', null=True, blank=True, on_delete=models.CASCADE)
def __str__(self):
return 'Category: {}'.format(self.name)
class MenuItem(models.Model):
name = models.CharField(max_length=200)
image = models.ImageField(upload_to='menu_images/', null=True, blank=True)
description = models.TextField(blank=True, null=True)
price = models.DecimalField(max_digits=6, decimal_places=0)
other_Price = models.DecimalField(max_digits=6, decimal_places=0, null=True, blank=True)
categories = models.ManyToManyField('Category', related_name='item', null=True, blank=True)
def __str__(self):
return 'MenuItem: {}'.format(self.name)
You need to carefully think about your model design. The way you have designed categories allows you to have unlimited sub-categories. Do you really need that flexibility? Because it comes at the cost of complexity. Think about how you will be interacting with the models.
With your current design, it would be challenging to render in a Django template without preprocessing it in Python using some gnarly recursion, because you have no way apriori to know how many nested sub categories you have. You could have sub-category, sub-sub-category, sub-sub-sub-category and so on.
Also, querying your models will be complicated. Say you have 'Cat1'->'Sub-cat1'->'Sub-sub-cat1'->'menuitem1'. How do you find all menu items that are a descendant of 'sub-cat1'? All I can think of is MenuItem.objects.filter(parent__parent=subcat1_obj). Not very Pythonic or clear to a reader. And you run into problems as you dont know how many layers of sub-categories you have.
Or how do you get just the menu categories? Category.objects.filter(parent=None). Its not obvious from this code what we are talking about.
I would, if your use-case allows it, simplify your model design in this way:
class MenuCategory(models.Model):
category = models.ForeignKey(Category, ...)
...
class MenuSubCategory(models.Model):
menu_category = models.ForeignKey(MenuCategory, ...)
...
class MenuItem(models.Model):
menu_categories = models.ManyToManyField(MenuCategory, ...)
menu_subcategories = models.ManyToManyField(MenuSubCategory, ...)
...
Now rendering your models in a template would be straight forward (given context['menu_categories'] = MenuCategory.objects.all()):
{% for cat in menu_categories %}
{% for item in cat.menuitem_set.all %}
{{ item }}
{% endfor %}
{% for subcat in cat.menusubcategory_set.all %}
{% for item in subcat.menuitem_set.all %}
{{ item }}
{% endfor %}
{% endfor %}
{% endfor %}
Now querying your models will also be more clear. You could also if needed add a Menu model and have different menus.

Django - Join two table in view and use it in template

I'm using python 3.4.5 with Diango 2.0.2
I have 2 tables with a foreign key. For some reasons, I need to use 2 tables to store these data.
I want to generate a table which contain the following information.
program.name , program.program_id , program.filter(user=request.user.id).status(if exist, if not exist, keep it NULL)
models.py
class Program(models.Model):
name = models.CharField(max_length=128, null=True, blank=True, default=None)
program_id = models.AutoField(primary_key=True)
class ProgramInfo(models.Model):
pid = models.ForeignKey(Program, on_delete=models.CASCADE, null=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
status = models.CharField(max_length=10, default=1003)
views.py
def program_list(request):
program = Program.objects.all()
return render(request, 'panel/program_list.html', {'program': program})
template
{% for prog in program %}
<tr>
<td> {{ prog.name }} </td>
<td> {{ prog.program_id }} </td>
<td> {{ "program's status of existing user" }} </td>
</tr>
{% endfor %}
How to generate a table which contain the following information?
program.name , program.program_id , program.filter(user=request.user.id).status
I have 2 solutions,
(1) generate a table and pass it to template
(2) send the program table to template, and use something like program.filter(user=request.user.id).status in "td"
But I don't know how to do it for these 2 solutions.
The table should be like this
NameA, 123, yes
NameB, 234,
NameC, 345, no
NameD, 456,
NameE, 567, no
ProgramInfo has a ForeignKey field pointing to a Program instance
pid = models.ForeignKey(Program, on_delete=models.CASCADE, null=True)
Thus, you can have multiple ProgramInfo instances linked to a single Program instance. To retrieve that list, simply use:
program_instance = Program.objects.get(id=123)
# gives you the list of ProgramInfo instances:
programinfo_list = program_instance.programinfo_set
You can find more information about Many to One relationships and Related objects in Django doc. FYI, instance.programinfo_set is a RelatedManager (a child class of the more generic Manager). Thus, it provides an interface to lookup instances contained in this relationship.
If you need to have only 1 to 1 relationship between your models, use a OneToOne field instead:
pid = models.OneToOneField(Program, on_delete=models.CASCADE, null=True)

How to display different custom users after logging in Django

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 %}

Categories

Resources