Generating continuous default names for new objects in Django - django

I want to create a model with a default name field. e.g If its the first object, the default name will be:
new, then new1, new2 ...
How do I accomplish this in Django models?

You can try this:
models.CharField(max_length=10, default=generator)
index = 0
def generator():
# you can define incremental logic or static value.
global index
index += 1
return 'new' + str(index)
# result
# ------
# new1
# new2
# new3
# new4
# ....
# ....
# ....

Related

Use non model django fields in django filter

I have a variable 'cptCodeTBX' which is not present as fields in django models. I need to apply filter on 'cptCodeTBX' variable. Something roughly equivalent to
cptCodeTBX = '00622'
select * from cpt where cpt.code like cptCodeTBX or cptCodeTBX is != ''
In dot net entity framework we could do it by
b = cptContext.CPTs.AsNoTracking().Where(
a =>
(String.IsNullOrEmpty(cptCodeTBX) || a.Code.StartsWith(cptCodeTBX))
This may not be the most performant solution, but I was able to get it working.
Step 1: Read the Django Filter docs.
https://django-filter.readthedocs.io/en/stable/index.html
Step 2: Add a property to your Django model named cptCodeTBX.
from django.db import models
class MyModel(models.Model):
field = models.CharField(max_length=60)
#property
def cptCodeTBX(self):
"""
Does all the code tbx cpt stuff, can do whatever you want.
"""
cptCodeTBX = 2323 #whatever value you want
return cptCodeTBX
Step 3: Add a Django Filter.
import django_filters
class CptCodeTBXFilter(django_filters.FilterSet):
"""
Filter that will do all the magic, value comes from url query params.
Replace filters.NumberFilter with any filter you want like
filters.RangeFilter.
"""
cptCodeTBX = django_filters.NumberFilter(
field_name="cptCodeTBX",
method="filter_cptCodeTBX",
label="Cpt Code TBX",
)
def filter_cptCodeTBX(self, queryset, name, value):
objects_ids = [
obj.pk for obj in MyModel.objects.all() if obj.cptCodeTBX == value
]
if objects_ids:
queryset = MyModel.objects.filter(pk__in=objects_ids)
else:
queryset = MyModel.objects.none()
return queryset
Step 4: Pass the value through the url as a query parameter.
http://example.com/?cptCodeTBX=00622

Django Models with Choices as Integer

I am trying to make a feedback app in Django, but I can not make my evaluations.
In my models.py, I have 5 choices from very bad to excellent. But I want them to be usable as numbers so I can evaluate the overall value.
After reading Set Django IntegerField by choices=... name I changed my Ratings from VERYBAD = 'Very bad' to VERYBAD = 1 but no I can't even save my value/form.
Feedback(models.Model):
event = models.ForeignKey(Event)
# Choice
VERYBAD = 'Very bad' #old
BAD = 2 #new
OKAY = 3
GOOD = 4
EXCELLENT = 5
RATING = (
(VERYBAD, 'Very bad'),
(BAD, 'Bad'),
(OKAY, 'Okay'),
(GOOD, 'Good'),
(EXCELLENT, 'Excellent'),
)
# The ratings
organisation = models.CharField(
max_length=9,
choices=RATING,
default=OKAY,
)
....
So in my view, I thought I can do the math but I can not.
def rating(request, event_id):
myevent = Event.objects.get(id=event_id)
feedback_items = Feedback.objects.filter(event=myevent)
num_of_items = len(feedback_items)
def evaluate(feedback_items):
# The overall rating
organisation = 0
for item in feedback_items:
organisation += item.organisation
organisation /= num_of_items
context = {'feedback_items':feedback_items,
'num_of_items': num_of_items,
'myevent': myevent,}
return render(request, 'feedback/rating.html', context)
`
You have to make organisation an IntegerField, obviously - else you can't hope to do integer operations. If you already have this in production, use a set of migrations to add a new IntegerField, populate it from the existing CharField values (using a dict for mapping old string values to new int values), and finally getting rid of the original field.
Also, you may want to learn how to properly use Django's ORM features like getting related models instances and performing aggregations at the DB level, ie:
from django.db.models import Sum, Count, Avg
def rating(request, event_id):
myevent = Event.objects.get(id=event_id)
# this is how you get related models...
feedback_items = myevent.feedback_set.all()
# and this is how you use SQL aggregation functions:
values = feedback_items.aggregate(
sum=Sum('organisation'),
count=Count('pk'),
avg=Avg('organisation')
)
# Now 'values' should be a dict with 'sum', 'count' and 'avg'
# keys, and values['avg'] should be equal to
# float(values['sum']) / values['count']
# FWIW you probably don't need the 'sum' field at all
# I mentionned it so you can check whether 'avg' value
# is correct...
context = {
'feedback_items':feedback_items,
'num_of_items': values['count'],
'avg': values['avg'],
'myevent': myevent,
}
# etc

Dont save in DB repeated rows with Django import-export

Im importing an xls file with django import-export and all working fine, now i need delete the rows that has the same strings, i mean
id - name
1 - Jhon
2 - Jhon
3 - Peter
Only insert in DB when importing the rows 2 and 3
Until now, i have this:
class ProyectosResource(resources.ModelResource):
#repeated_rows = fields.Field()
class Meta:
model = Proyectos
class ProyectosAdmin(ImportExportModelAdmin):
resource_class = ProyectosResource
I don't know if it's the right way to do this but I will do this in before_import function:
class ProyectosResource(resources.ModelResource):
#repeated_rows = fields.Field()
class Meta:
model = Proyectos
def before_import(self, dataset, dry_run):
"""
Make standard corrections to the dataset before displaying to user
"""
list = []
i = 0
last = dataset.height - 1
while i <= last:
#adding each name to a list
if ("the name is not in the list (take care about capitalizes letters)"):
dataset.rpush((dataset.get_col(0)[0], dataset.get_col(1)[0])) # add this line to the bottom
list = list.append(dataset.get_col(1)[0]) # add the name to the list
dataset.lpop() # erase it from the top (first line)
else :
#the name is already in the list
dataset.lpop() # simply erase it (first line) from the dataset
i = i + 1
Here is the doc of Tablib to manipulate Datasets !
You can do every test you want in before_import function, checking id for foreignKey relations...

Django Admin Column Sort Descending

When using Django admin with grappelli I would like that a click on a column header will sort the table by descending order.
(I don't want a default ordering to the columns by defining the ordering field in the Model Meta Class.)
The default behavior is Ascending.
The first click should order like this:
Rewrite the def result_headers(cl)
add these 2 lines:
.....
.....
th_classes = ['sortable']
order_type = ''
#new lines
default_order_type = getattr(attr, "admin_order_first_type", None)
new_order_type = default_order_type if default_order_type else 'asc'
#end of new lines
sort_priority = 0
sorted = False
...
...
now in the ModelAdmin you can:
list_display = ('number_of_players', ....)
def number_of_players(self, team):
return intcomma(team.number_of_players)
number_of_players.short_description = '# num of players'
number_of_players.admin_order_field = 'number_of_players'
number_of_players.admin_order_first_type = 'desc' #will make the column to be ordered desc first
I tested it and it works

DJANGO: referring to id

Here's the bit that's giving me an issue: error 'QuerySet' object has no attribute 'address'
bdns = Business.objects.filter(name='slow')
addx = bdns.address
addr = Address.objects.get(id=addx)
What should I do?
My model for Business:
class Business(models.Model):
phone = PhoneNumberField()
address = models.ForeignKey(Address)
name = models.CharField(max_length=64)
A queryset is a collection, even if that collection only contains one element. When you do Model.objects.filter(), it returns a queryset.
If you want to return a single object, use Model.objects.get().
So, for your purposes:
bdns = Business.objects.filter(name='slow') # returns a collection
b = dbns[0] # get the first one
the_address = b.address # the address
# or...
try:
bdns = Business.objects.get(name='slow') # get single instance
except Business.DoesNotExist:
bdns = None # instance didnt exist, assign None to the variable
except Business.MultipleObjectsReturned:
bdns = None # the query returned a collection
if bdns is not None:
the_address = bdns.address
# the_address is an instance of an Address, so no need to do the lookup with the id
print the_address.id # 7
print the_address.street # 17 John St
print the_address.city # Melbourne
bdns = Business.objects.filter(name='slow')
Returns you a QuerySet (the collection of Business objects) You need to iterate to get each element with address.
addr = Address.objects.get(id=addx)
Should work