I have different django models which are identical e.g
ItemCategory
InventoryCategory
MenuCategory
ExpenseCategory
All of these models carry same attributes.
I want to use single html page which is category_list.html for displaying these models as list. I don't want to use different pages like item_category_list.html, inventroy_category_list.html, menu_category_list.html and so on. Every page contains page header which is actual kind of title of page represented in h1 tag. I want to change with respect to currently loaded page.
Note: I am using Generic Views for Listing Items and I am currently using context for recognizing which view is sending response.
Any help would be appreciated.
views.py
class ItemCategoryList(ListView):
model = ItemCategory
template_name = 'app/category_list.html'
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super().get_context_data(**kwargs)
# Add in a QuerySet of all the books
context['page'] = 'Item'
return context
class InventoryCategoryList(ListView):
model = InventoryCategory
template_name = 'app/category_list.html'
class ExpenseCategoryList(ListView):
model = ExpenseCategory
template_name = 'app/category_list.html'
models.py
class ItemCategory(models.Model):
name = models.CharField(max_length=30)
description = models.CharField(max_length=300, null=True, blank=True)
image = models.ImageField(upload_to="uploads/item_categories/", null=True, blank=True)
is_active = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now_add=True)
class InventoryCategory(models.Model):
name = models.CharField(max_length=30)
description = models.CharField(max_length=300, null=True, blank=True)
image = models.ImageField(upload_to="uploads/inventory_categories/", null=True, blank=True)
is_active = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now_add=True)
class ExpenseCategory(models.Model):
name = models.CharField(max_length=30)
description = models.CharField(max_length=300, null=True, blank=True)
image = models.ImageField(upload_to="uploads/expense_categories/", null=True, blank=True)
is_active = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now_add=True)
Not class based but my solution for this simply would be :
models.py:
class Category(models.Model):
name = models.CharField(max_length=30)
description = models.CharField(max_length=300, null=True, blank=True)
image = models.ImageField(upload_to="uploads/categories/", null=True, blank=True)
is_active = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now_add=True)
urls.py:
url(r'^(?P<category>\w+)/$', views.ItemCategoryList, name='category')
home.html:
Item Category
Inventory Category
category_list.html:
{% block title %}{{category.name}}{% endblock %}
{% for l in list %}
{{l}}
{% endfor%}
views.py:
def ItemCategoryList(request, category):
list = Category.objects.filter(name=category)
category = category
context{
'list':list,
'category':category
}
return render(request, 'app/category_list.html',context)
Related
I have below models and form.
Brand > Section > Category > Article.
I can pull the existing data out of the database however I have hit a wall. I am trying to create a new article or update an existing article but I'm not sure how I can update the brand, then the Section. The Category I can update and it is connected directly to the Article model. I have been thinking about this for a few days now and tried different models but ultimately i can't think of the best way to connect the models and have them update in the model.
class Brand(models.Model):
def brand_image(instance, filename):
return 'uploads/brand/{0}/{1}'.format(instance.title, filename)
title = models.CharField(max_length=50, unique=True, blank=True, null=True)
image = models.ImageField(upload_to=brand_image, null=True, blank=True)
slug = AutoSlugField(populate_from='title', unique_with='title', blank=True, null=True)
my_order = models.PositiveIntegerField(default=0, blank=False, null=False)
class Meta:
ordering = ['my_order']
def __str__(self):
return self.title or ''
def get_absolute_url(self):
return reverse('brand-list', kwargs={'brand_slug': self.slug})
class Section(models.Model):
title = models.CharField(max_length=50,unique=True, blank=True,null=True)
slug = AutoSlugField(populate_from='title', unique_with='title',blank=True,null=True)
brand = models.ForeignKey(Brand, on_delete=models.CASCADE, related_name='section', blank=False, null=False)
my_order = models.PositiveIntegerField(default=0, blank=False, null=False)
class Meta:
ordering = ['my_order']
def __str__(self):
return self.title or ''
def get_absolute_url(self):
return reverse('section-list', kwargs={'section_slug': self.slug})
class Category(models.Model):
title = models.CharField(max_length=50, blank=True,null=True)
slug = AutoSlugField(populate_from='title', unique_with='title',blank=True,null=True)
my_order = models.PositiveIntegerField(default=0, blank=False, null=False)
section = models.ForeignKey(Section, on_delete=models.CASCADE,related_name='category', blank=False ,null=False)
class Meta:
ordering = ['my_order']
def __str__(self):
return self.title or ''
def get_absolute_url(self):
return reverse('category-list', kwargs={'category_slug': self.slug})
class Article(models.Model):
title = models.CharField(max_length=100, unique=True, db_index=True)
description = models.CharField(max_length=100, blank=True, null=False)
category = models.ForeignKey(Category, on_delete=PROTECT, related_name='article', null=False, default=1)
slug = AutoSlugField(populate_from='title', unique_with='created__month')
content = HTMLField(null=True,blank=True)
internal = models.BooleanField(default=False)
status = models.CharField(max_length=30, choices=STATUS_CHOICES, default='Draft')
author = models.ForeignKey(User, related_name='author' ,on_delete=PROTECT,null=True)
updated_by = models.ForeignKey(User, related_name='updated_by',on_delete=PROTECT,null=True)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
video = models.FileField(blank=True, null=True, upload_to='articles/videos')
favourites = models.ManyToManyField(User, related_name='art_favourite', default=None, blank=True)
tags = TaggableManager(related_name='tags', help_text='Comma or space separated list', blank=True)
pinned = models.BooleanField(default=False)
def __str__(self) -> str:
return self.title
def get_absolute_url(self):
return reverse('articles-detail', kwargs={'article_slug': self.slug})
class ArticleForm(forms.ModelForm):
title = forms.CharField(label='Article Title', max_length=100,)
description = forms.CharField(label='Description', max_length=100,required=False)
content = forms.CharField(label='Article Content',widget=CKEditorUploadingWidget(attrs={'cols': 80, 'rows': 30}))
video = forms.FileField(help_text="Valid file Extension - .mp4", required=False, validators=[validate_file_extension])
category = GroupedModelChoiceField(queryset=Category.objects.exclude(section=None).order_by('section'),choices_groupby='section')
internal = forms.BooleanField(required=False, help_text='Is this for internal use only?', label='Internal Article')
class Meta:
model = Article
exclude = ['slug','author','created','updated','updated_by','favourites','votes','views','section']
widgets = {"tags": TagWidget(attrs={"data-role": "tagsinput"})}
Any help or guidance would be greatly appreciated.
Your Article model has a foreign key link to Section for some reason. However your stated heirarchy and models use the following one-to-many relations, which creates a direct link up the chain.
Brand < Section < Category < Article.
This means that by choosing the Category you could also choose Brand and Section. If your Article had a foreign key link to Category instead, then all the information above about groups above Article could be obtained via the article, eg, article.category__section__brand. Changing the category would, by default, update section and brand. You could do this in a single dropdown that contained Category.objects.all - perhaps with the dropdown option text also containing brand and section info for clarity and sorting purposes.
I have an app that allows users to signup and register for courses (from a 'TrainingInstance' model). These events have names etc and are categorised as Past or Current in the database (in the 'Training' model). When I show the BuildOrderForm in my template, I want only options for Current trainings to be shown in the dropdown menu. How can this be done in Django without javascript or Ajax?
I have the following form in forms.py:
class BuildOrderForm(forms.ModelForm):
class Meta:
model = Order
fields = ['training_registered']
And the following models in models.py:
class Training(models.Model):
""" Model which specifies the training category (name) and whether they are Past or Present"""
YEAR = (
('current', 'current'),
('past', 'past'),
)
name = models.CharField(max_length=200, null=True)
year= models.CharField(max_length=200, null=True, choices=YEAR, default='current')
def __str__(self):
return self.name
class TrainingInstance(models.Model):
""" Creates a model of different instances of each training ( May 2021 etc) """
name = models.CharField(max_length=200, null=True, blank=True)
venue = models.CharField(max_length=200, null=True, blank=True)
training = models.ForeignKey(Training, on_delete= models.CASCADE, null = True)
training_month = models.CharField(max_length=200, null=True, blank=True)
participant_date = models.CharField(max_length=20, null=True, blank=True)
staff_date = models.CharField(max_length=20, null=True, blank=True)
graduation_date = models.CharField(max_length=200, null=True, blank=True)
def __str__(self):
return self.name
class Order(models.Model):
REGSTATUS = (
('registered', 'registered'),
('enrolled', 'enrolled'),
('holding', 'holding'),
('withdrawn', 'withdrawn'),
('waiting', 'waiting'),
)
customer = models.ForeignKey(Customer, on_delete= models.CASCADE, null = True)
training_registered = models.ForeignKey(TrainingInstance, on_delete= models.SET_NULL, blank = True, null = True)
registration_date = models.DateTimeField(null=True,blank=True)
regstatus = models.CharField(max_length=200, null=True, choices=REGSTATUS, default='registered')
def __str__(self):
return self.customer.username
Here is what I have done - which works but I'm also open to feedback about good/bad practice.
class BuildOrderForm(forms.ModelForm):
class Meta:
model = Order
fields = ['training_registered']
def __init__(self,*args,**kwargs):
super (BuildOrderForm,self ).__init__(*args,**kwargs)
self.fields['training_registered'].queryset = TrainingInstance.objects.filter(training__year ="current")
How should I query when I use pk with annotate?
I need to redirect to user profile when a guest click in link.
Models
class Posty(models.Model):
title = models.CharField(max_length=250, blank=False, null=False, unique=True)
sub_title = models.SlugField(max_length=250, blank=False, null=False, unique=True)
content = models.TextField(max_length=250, blank=False, null=False)
image = models.ImageField(default="avatar.png",upload_to="images", validators=[FileExtensionValidator(['png','jpg','jpeg'])])
author = models.ForeignKey(Profil, on_delete=models.CASCADE)
updated = models.DateTimeField(auto_now=True)
published = models.DateTimeField(auto_now_add=True)
T_or_F = models.BooleanField(default=False)
likes = models.ManyToManyField(Profil, related_name='liked')
unlikes = models.ManyToManyField(Profil, related_name='unlikes')
created_tags = models.ForeignKey('Tags', blank=True, null=True, related_name='tagi', on_delete=models.CASCADE)
class CommentPost(models.Model):
user = models.ForeignKey(Profil, on_delete=models.CASCADE)
post = models.ForeignKey(Posty, on_delete=models.CASCADE, related_name="comments")
content1 = models.TextField(max_length=250, blank=False, null=False)
date_posted = models.DateTimeField(default=timezone.now)
date_updated = models.DateTimeField(auto_now=True)
def __str__(self):
return str(self.content1)
class Profil(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
age = models.PositiveIntegerField(blank=True, null=True)
country = models.CharField(max_length=50)
user = models.OneToOneField(Account, on_delete=models.CASCADE)
avatar = models.ImageField(default="avatar.png", upload_to="images",validators=[FileExtensionValidator(['png', 'jpg', 'jpeg'])])
slug = models.SlugField(blank=True)
gender = models.CharField(max_length=6, choices=GENDER)
friends = models.ManyToManyField(Account, blank=True, related_name="Friends")
social_facebook = models.CharField(max_length=250, null=True, blank=True)
social_instagram = models.CharField(max_length=250, null=True, blank=True)
social_twitter = models.CharField(max_length=250, null=True, blank=True)
social_youtube = models.CharField(max_length=250, null=True, blank=True)
social_linkedin = models.CharField(max_length=250, null=True, blank=True)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
Views
if tag == None:
my_tag = Posty.objects.annotate(
latest_comment = Subquery(CommentPost.objects.filter(post=OuterRef('id')).values('content1').order_by('-date_posted')[:1]),
my_author=Subquery(CommentPost.objects.filter(post=OuterRef('id')).values('user__user__username').order_by('-date_posted')[:1]),
)
I got a correct username, but I can't get a correct redirect:
Unfortunately, you need to annotate the CommentPost's id information as well with the queryset just like you added the username information. That will end up being a lot of subquery added to the original queryset. Rather I would suggest to use prefetch related to preload the CommentPost information with the original queryset (for reducing DB hits) and directly access that information from template. For example:
# view
my_tag = Posty.objects.prefetch_related('commentpost_set')
# template
{% for post in my_tag %}
<span> {{post.commentpost_set.last.content1}}<span>
<span> {{post.commentpost_set.last.user.username}}<span>
{% endfor %}
Also, last is a queryset function which returns the last object of a given queryset. I can access the CommentPost queryset from a Posty object by reverse querying.
I have got 2 models. Asset and Asset_Type. In my asset_type detail view i would like to list all assets of that asset type. I think I have to use models.Asset.queryset().filter() but i can't get it to work.
On my template I would like to loop though the list with a 'for' (example: object in list) and print the values like this {{ object.name }}
models.py
class Asset(models.Model):
# Relationships
room = models.ForeignKey("asset_app.Room", on_delete=models.SET_NULL, blank=True, null=True)
model_hardware = models.ForeignKey("asset_app.Model_hardware", on_delete=models.SET_NULL, blank=True, null=True)
# Fields
name = models.CharField(max_length=30)
serial = models.CharField(max_length=30, unique=True, blank=True, null=True, default=None)
mac_address = models.CharField(max_length=30, null=True, blank=True)
purchased_date = models.DateField(null=True, blank=True)
may_be_loaned = models.BooleanField(default=False, blank=True, null=True)
notes = models.TextField(max_length=448, null=True, blank=True)
ip = models.CharField(max_length=90, null=True, blank=True)
created = models.DateTimeField(auto_now_add=True, editable=False)
last_updated = models.DateTimeField(auto_now=True, editable=False)
class Meta:
ordering = ["name"]
def __str__(self):
return str(self.name)
def get_absolute_url(self):
return reverse("asset_app_asset_detail", args=(self.pk,))
def get_update_url(self):
return reverse("asset_app_asset_update", args=(self.pk,))
class Asset_type(models.Model):
# Fields
name = models.CharField(max_length=30)
last_updated = models.DateTimeField(auto_now=True, editable=False)
created = models.DateTimeField(auto_now_add=True, editable=False)
notes = models.TextField(max_length=448, null=True, blank=True)
class Meta:
ordering = ["name"]
def __str__(self):
return str(self.name)
def get_absolute_url(self):
return reverse("asset_app_asset_type_detail", args=(self.pk,))
def get_update_url(self):
return reverse("asset_app_asset_type_update", args=(self.pk,))
class Model_hardware(models.Model):
# Relationships
asset_type = models.ForeignKey("asset_app.Asset_type", on_delete=models.SET_NULL, blank=True, null=True)
brand = models.ForeignKey("asset_app.Brand", on_delete=models.SET_NULL, blank=True, null=True)
# Fields
name = models.CharField(max_length=30)
notes = models.TextField(max_length=448, null=True, blank=True)
created = models.DateTimeField(auto_now_add=True, editable=False)
last_updated = models.DateTimeField(auto_now=True, editable=False)
class Meta:
ordering = ["name"]
def __str__(self):
return str(self.name) + " :: " + str(self.brand.name) + " :: " + self.asset_type.name
def get_absolute_url(self):
return reverse("asset_app_model_hardware_detail", args=(self.pk,))
def get_update_url(self):
return reverse("asset_app_model_hardware_update", args=(self.pk,))
views.py
class Asset_typeDetailView(generic.DetailView):
model = models.Asset_type
form_class = forms.Asset_typeForm
You can simply iterate over the related objects in the template by using the default related name which is the model name in lowercase with _set appended. So asset_type.model_hardware_set.all() will give you all Model_hardware instances related to Asset_type and similarly for model_hardware.asset_set.all():
{% for model_hardware object.model_hardware_set.all %}
{% for asset in model_hardware.asset_set.all %}
{{ asset.name }}
{% endfor %}
{% endfor %}
But this can become slow, since we run into the N + 1 problem that is for each model hardware we will be making queries to get it's assets. We can use prefetch_related_objects on your model instance to prefetch all the related objects (in fewer queries) this and make it faster:
from django.db.models import prefetch_related_objects
from django.views.generic import DetailView
class YourDetailView(DetailView):
model = Asset_type
template_name = '<your_template_name>.html'
def get_object(self, queryset=None):
obj = super().get_object(queryset=queryset)
prefetch_related_objects([obj], 'model_hardware__asset')
return obj
Note: Class names in python should ideally be in PascalCase not Some_case (Don't think there is any such convention as you make
here), hence ModelHardware instead of Model_hardware and
AssetType instead of Asset_type would be better names.
Is it possible to translate DB entries? I have a dependent dropdown story that i need to translate. But i cant translate the dropdown fields, the fields come from other models and har hard coded. I can use HTML with JQ to achive this but i want to skip the manual labor to update the forms everytime new profession or professioncategories are added.
class Profession(models.Model):
name = models.CharField(max_length=30),
def __str__(self):
return self.name
class Professioncategory(models.Model):
profession = models.ForeignKey(Profession, on_delete=models.CASCADE)
name = models.CharField(max_length=30)
def __str__(self):
return self.name
class Skills(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
active = models.BooleanField(_('Active'), default=True)
profession = models.ForeignKey(Profession, on_delete=models.SET_NULL, null=True)
professioncategory = models.ForeignKey(Professioncategory, on_delete=models.SET_NULL, null=True)
posted_on = models.DateTimeField(_('Registrerad'), auto_now_add=True)
updated_on = models.DateTimeField(_('last updated'), auto_now=True)
years_of_exp = models.CharField(_('years of experiance'), max_length=20, choices=YEARS_OF_EXP, null=True, blank=True)