Django-tables2: Change text displayed in column title - django

I am working with a MySQL view (Create View as Select ...) and have successfully manged to connect the view to a model like this:
#models.py
class Dashboard(models.Model):
devenv = models.CharField(max_length=30, primary_key=True)
numberofissues = models.BigIntegerField()
class Meta:
managed=False
db_table = 'stability_dashboard'
I have also managed to display data in a table using the boiler plate code from the example:
#tables.py
class DashboardTable(tables.Table):
class Meta:
model = Dashboard
attrs = {'class': 'paleblue'}
#views.py
def dashboard(request):
table = DashboardTable(Dashboard.objects.all())
RequestConfig(request).configure(table)
return render(request, 'uptime/dash.html', {'table': table})
I would now like to change the title displayed in each column to something more understandable including spaces e.g. Instead of 'devenv' => 'Development Environment'

Just add the columns whose names you want to override in your tables.py. For instance
#tables.py
import django_tables2 as tables
from models import Dashboard
class DashboardTable(tables.Table):
devenv = tables.Column(verbose_name= 'Development Environment' )
class Meta:
model = Dashboard
attrs = {'class': 'paleblue'}
Another (probably more DRY) solution is to leave tables.py as is and add verbose_name in your model definition:
#models.py
class Dashboard(models.Model):
devenv = models.CharField(max_length=30, primary_key=True, verbose_name='Development Environment')
numberofissues = models.BigIntegerField(verbose_name='Number of Issues')
class Meta:
managed=False
db_table = 'stability_dashboard'

Related

Django import-export - Import model with child from excel

I have two models: Project and Activity.
When registering a project, one or more associated activities can be added.
How can I import projects from xlsx, which include at least one activity?. I'm using the third party library django-import-export
I configure the project resource to export all the activities of each project in one cell separated by /, but I need the opposite, import all the activities of each project. I think that I must first save the Project for obtain the id, next extract the info from cell and finally save each activity associated, but I don't know how to do that.
My simplified models are:
class Project(models.Model):
reg_date= models.DateField(
default=date.today)
name = models.CharField(
max_length=100,
unique=True)
def __str__(self):
return self.name
class Activity(models.Model):
schedule= models.ForeignKey(
Project,
on_delete=models.CASCADE)
date = models.DateField()
description = models.TextField(max_length=1000)
class Meta:
unique_together = ('schedule', 'date', 'description')
class ProjectResource(resources.ModelResource):
activities = Field()
class Meta:
model = Project
import_id_fields = ['name']
exclude = ('id',)
skip_unchanged = True
report_skipped = True
fields = ('reg_date',
'name',
'activities')
def dehydrate_activities(self, obj):
if obj.id:
return "/".join([
'({0} - {1})'.format(activity.date, activity.description) for activity in obj.projectactivity_set.all()
])
def skip_row(self, instance, original, row, import_validation_errors=None):
if original.name:
return True
return False
An example of exported file is:
reg_date
name
activities
2023-01-10
Project 1
2023-01-12-This is the first activity/2023-01-14-This is the second activity
2023-01-10
Project 2
2023-01-13-This is the first activity/2023-01-15-This is the second activity
You need to create the Activity instances before you create the Project instances.
Then in your Project resource class you can define that a particular field is for foreign keys.
I've got an example;
from import_export import fields, resources, widgets
from apps.event.models import Occurrence
from ..models import Token
class TokenResource(resources.ModelResource):
""" Integrate django-import-export with the Token model """
occurrence = fields.Field(
column_name='occurrence',
attribute='occurrence',
widget=widgets.ForeignKeyWidget(Occurrence, 'id')
)
class Meta:
fields = (
'id',
'occurrence',
'code',
)
model = Token
When using the ForeignKeyWidget, the first argument is the related model, then the second is a unique value that you can use to lookup the instance. It's that unique value that you then put in your import file to reference the related objects.
And my Token model has that relationship;
class Token(EnabledMixin, TimestampMixin, models.Model):
""" Token for event entry. """
class Meta:
""" Meta class definition. """
app_label = 'console'
verbose_name = _("Token")
verbose_name_plural = _("Tokens")
unique_together = ('code', 'occurrence')
ordering = [
'id',
]
occurrence = models.ForeignKey(
to='event.Occurrence',
verbose_name=_("Event Occurrence"),
blank=True,
null=True,
related_name='tokens',
on_delete=models.SET_NULL,
)

Need to get the Foreign key value instead of ID in the database table using Django

model
class Project(models.Model):
project_name = models.CharField(max_length=20)
client= models.ForeignKey(Client,on_delete=CASCADE,related_name="Client1",default=None)
user=models.ManyToManyField(Default_User,related_name='users',default=None)
description=models.TextField()
type=models.TextField() #dropdown
start_date = models.DateTimeField(max_length=10)
end_date=models.DateTimeField(max_length=10)
technical_contact_name = models.CharField(max_length=30)
email=models.EmailField(max_length=254,default=None)
phone = PhoneField(blank=True)
delivery_head_contact_name=models.CharField(max_length=30)
class Meta:
db_table ='Project'
def __str__(self):
return self.project_name
model
class Job(models.Model):
job_name=models.CharField(max_length=50)
user= models.ForeignKey(Default_User,on_delete=CASCADE)
project = ChainedForeignKey(Project,chained_field="user", chained_model_field="user",related_name='projects',show_all=False, auto_choose=True, sort=True)
date = models.DateField(max_length=10,default=None)
class Meta:
db_table ='Job'
def __str__(self):
return '{}'.format(self.job_name)
serializers
class ProjectSerializers(serializers.ModelSerializer):
class Meta:
model= Project
fields= '__all__'
class Job_Serializers(serializers.ModelSerializer):
job = serializers.StringRelatedField()
class Meta:
model= Job
fields= ('id','job_name','user','project','date','job',)
I need to get the foreign key value displayed in the database table of Job model but as per the above code it is displaying the Foreign key ID. For example I linked the project model in the Job model and in the db table it is showing the Project_id as(1,2,3) but i need to return the values of that id as(app, learning etc). Please help me to get the values of the foreign key value instead of ID in the database table.
The database will by default take the unique field from the model and django provide id as unique key for models. It is for data consistency. So you can let that happen and in job serializera use SerializerMethodField to retrieve the value of project name based on instance of job objects.
Depends on what you want to achieve with it. If it is just to return another field value from project, then you can add it to the serializer as in below example. I am returning project_name as well.
class JobSerializers(serializers.ModelSerializer):
job = serializers.StringRelatedField()
project_name = serializers.SerializerMethodField()
class Meta:
model= Job
fields= ('id','job_name','user','project','date','job', 'project_name')
def get_project_name(self, job):
return job.project.project_name
If you want to return the whole project object then you have to include
project = ProjectSerializers()

Boolean Filter on Django Admin

I'm trying to build a filter that corresponds to the has_images method on my Django admin, but I can't because it strictly says that has_images is not a field of the model. I tried setting it up as a property, but it also didn't work.
I thought about defining has_images as a field and really calculating it, based on the changes on the model, but I think that would be not optimal.
What would be a good solution here?
models.py
class Product(models.Model):
name = models.CharField("Name", max_length=255)
def has_images(self):
return self.images.all().count() > 0
has_images.boolean = True
class ProductImage(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name="images")
file = models.ImageField("Product Image")
admin.py
class ProductImageInline(admin.TabularInline):
model = ProductImage
fields = ('file',)
extra = 1
class ProductAdmin(VersionAdmin):
list_display = ('id', 'name', 'has_images',)
inlines = (ProductImageInline,)
Expected result:
Can you share the contents of the admin.py file?
Or let me explain it as follows. Add a feature called list_filter = ('images') into the ProductAdmin class you created in admin.py. If this feature doesn't work (I'm not sure as I haven't tried it), if you create an Admin Class for ProductImages directly, you can already view the pictures and the corresponding Product on that page.
----------- EDIT ----------------
This is how I solved the problem.
models.py
from django.db import models
class Product(models.Model):
name = models.CharField("Name", max_length=255)
is_image = models.BooleanField(default=False, editable=False)
def save(self, *args, **kwargs):
if self.images.count():
self.is_image = True
else:
self.is_image = False
super(Product, self).save(*args, **kwargs)
class ProductImage(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name="images")
file = models.ImageField("Product Image")
def save(self, *args, **kwargs):
super(ProductImage, self).save(*args,**kwargs)
self.product.save()
admin.py
from django.contrib import admin
from .models import *
class ProductImageInline(admin.TabularInline):
model = ProductImage
fields = ('file',)
extra = 1
class ProductAdmin(admin.ModelAdmin):
list_display = ('id', 'name',)
list_filter = ('is_image',)
inlines = (ProductImageInline,)
admin.site.register(Product, ProductAdmin)
Here I added an is_image BooleanField field with False by default. Every time the save method of the Product model runs, it checks whether there is an image in the ProductImage to which the Product model is attached. If there is an image in it, is_image is set as True.

ModelMultipleChoiceFilter - Field 'id' expected a number but got 'Diner'

So I have a simple Ad model and a FilterView showing all the ads. The ads can be filtered by different tags stored in a separate model joined by a ManyToManyField.
I'm using django-filter to set up a small ModelMultipleChoiceFilter and let users select different tags to filter the Ads. This is working however it uses the tag__id. I would like it to use the tag__slug field.
Therefore I've added the attribute "to_field_name='slug'" but I get the following;
Field 'id' expected a number but got 'diner'.
The following code does work but only filters by tag__id like:
/?tags=6
and I would rather see something like this;
?tags=diner
models.py
class Ad(models.Model):
category = models.ForeignKey('Category', on_delete=models.SET_NULL, null=True)
description = RichTextField()
tags = models.ManyToManyField('Tag')
title = models.CharField(max_length=200)
slug = models.SlugField(max_length=200, null=True)
class Meta:
ordering = ['-title']
def __str__(self):
return self.title
class Tag(models.Model):
name = models.CharField(max_length=200, help_text='Titel van de tag')
slug = models.SlugField(max_length=200, null=True)
def __str__(self):
return self.name
filters.py
from django import forms
from discovery.grid.models import Ad, Tag
import django_filters
class AdFilter(django_filters.FilterSet):
tags = django_filters.ModelMultipleChoiceFilter(
# to_field_name='slug',
queryset=Tag.objects.all(),
widget=forms.CheckboxSelectMultiple)
class Meta:
model = Ad
fields = [
'tags'
]
How can I achieve filtering based on the model name or slug instead of the id?
With best regards,
Maybe you can try like this:
class AdFilter(django_filters.FilterSet):
tags = CharFilter(method='my_custom_filter')
def my_custom_filter(self, queryset, name, value):
return queryset.filter(**{
'tags__slug__iexact': value,
})
class Meta:
model = Ad
fields = [
'tags'
]
More information can be found in documentation.

How to save MultipleChoiceField to db

I want to create a settings page where a user can select multiple values of skills they have. It will have a main category and then subcategories. I need to save those into my database, so I can query them and show their selected skillset again.
I know how to create the MultipleChoiceField but not how to save them to the database. How would I go on about that?
Forms.py
from django import forms
class skills(forms.Form):
jobs = [
('Håndværker', (
('Gulv', 'Gulv'),
('Væg', 'Væg'),
)
),
('Murer', (
('Mur', 'Mur'),
('blabla', 'blabla'),
)
),
]
job = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple,
choices=jobs)
Views.py
from .forms import skills
def index(request):
if request.method == 'POST':
form = skills(request.POST)
if form.is_valid():
picked = form.cleaned_data.get('job')
# do something with your results
else:
form = skills
return render(request, 'settings/index.html', {"form":form})
It currently looks like this when the page loads which is good. Next step is just how I would save it to the database, so I can display this again with their previous chosen values.
Since you don't have any models setup yet, you can look into django-multiselectfield, which would store the selected choices "as a CharField of comma-separated values". Then you'd just need to pass those values from your form.
Alternatively you can look into PostgreSQL's Array field.
I would recommend you have a Jobs model and a Skills Model. Then have a skills field on the job model which will be a ManyToManyField to the Skills model. The form for this can then be autogenerated for you by Django as a ModelForm.
# Create your models here.
class Skill(models.Model):
name = models.CharField(max_length=20, null=False, blank=False)
def __str__(self):
return self.name
class Job(models.Model):
name = models.CharField(max_length=20, null=False, blank=False)
skills = models.ManyToManyField(Skill)
def __str__(self):
return self.name
class Person(models.Model):
name = models.CharField(max_length=20, null=False, blank=False)
skills = models.ManyToManyField(Skill)
def __str__(self):
return self.name
You can then add them to the db as
skill1 = Skill.objects.create(name="Skill One")
skill2 = Skill.objects.create(name="Skill Two")
skill3 = Skill.objects.create(name="Skill Three")
skill4 = Skill.objects.create(name="Skill Four")
job1 = Job.objects.create(name="Job One")
job1.skills.add(skill1)
job1.skills.add(skill2)
job2 = Job.objects.create(name="Job Two")
job2.skills.add(skill3)
job2.skills.add(skill4)
Have a form to display
class PersonForm(forms.ModelForm):
class Meta:
model = Person
fields = ["name", "skills"]
You can cutomize the form or the template to your linking
in models.py just create the field with CharField
from django.db import models
class UserProfileInfo(models.Model):
Gender = models.CharField(max_length=10,default='')
in forms.py just create CHOICE like below
class UserProfileInfoForm(forms.ModelForm):
YESNO_CHOICES = (('male', 'male'), ('female', 'female'))
Gender = forms.ChoiceField(choices=YESNO_CHOICES)
class Meta():
model = UserProfileInfo
fields = ('Gender',)
in views.py import this form and display it.
or you can definitely go with
https://pypi.org/project/django-multiselectfield/