Django prefilled Admin Tabular Inline - django

My goal is that the first column of my tabular inline sheet is filled with data from another table. I've attached a screenshot where you can see that for tablename=game I want to insert the game number (eg. 1), the metric (e.g time), the player_names and the values (-> scores) per player. Number and metric applies to the hole game. Each game within Table=Game shall contain
number
metric
player_1:name and score
player_2:name and score
...
and so on.
The player names are stored in a table called players. Is there a way to pre-fill the first row of my tabular inline with my player_names. Otherwise i have to write it down for each game.
Django admin panel_tabularInline
I've created several models in models.py:
class Game(models.Model):
player_name = models.CharField(max_length=30)
class Game (models.Model):
NUMBER = (
(1, 1),
(2, 2),
(3, 3),
(4, 4),
(5, 5),
(6, 6))
METRIC = (
('Kills', 'Kills'),
('Time', 'Time'),
('Deaths', 'Deaths')
)
number = models.BigIntegerField(default=1, choices=NUMBER)
metric = models.CharField(max_length=30, choices=METRIC)
class GameItem (models.Model):
value = models.CharField(max_length=30)
game = models.ForeignKey(Game, on_delete=models.CASCADE)
def __str__(self):
This is my admin.py file:
from django.contrib import admin
from .models import *
class GameItemInline(admin.TabularInline):
model = GameItem
extra = 6 #I've got 6 players atm.
class GameAdmin(admin.ModelAdmin):
inlines = [GameItemInline]
class Meta:
model = Game
admin.site.register(Game, GameAdmin)

Related

how to set django model field value to automatically calculate a value based on values of other field in the different model

I am trying to figure out how I can make a django field model to automatically populate by summing values of another model's fields. For Example, if I have a model with 2 fields (first, second) and I want to automatically sum them and input them in a other model.
enter image description here
First of all, you need to make two tables with ForeignKey,
class Model1(models.Model):
First = models.IntegerField()
Second = models.IntegerField()
class Model2(models.Model):
Model1 = models.ForeignKey(Model1, on_delete=models.SET_NULL)
Sum = models.IntegerField()
then you can do it with normal views like this :
def saveSum(request):
first = 5
second = 6
model1 = Model1(first=first,second=second)
model1.save()
#then sum the values and save it to the second model
sum = first + second
model2 = Model2(Model1=model1,sum=sum)
model2.save()
or you can do it with SIGNALS and this is simple tutorial for this but be carefull with signals : Click this

Django Admin Panel Choices from Database

I have a model that has a IntegerField and in the admin. I want to add choices to the widget as "University" field. There is no problem if I add the universities in list as uniList.
But I do not know how can add these universities from UniversityList Class. I want to add new universities to UniversityList on admin panel and then I want to choose these added universities in Mainland2 admin page.
In this case I received error message as
in get raise self.model.MultipleObjectsReturned(mainpage.models.MultipleObjectsReturned: get() returned more than one UniversityList -- it returned 5!
Thank you for in advance...
from django.db import models
from django import forms
from django_countries.fields import CountryField
from django.core.exceptions import ValidationError
class UniversityList(models.Model):
name = models.CharField(max_length=50)
class Mainland2(models.Model):
unilist = [
(0, "---"),
(1, "Uni 1"),
(2,"Uni 2"),
(3,"Uni 3"),
]
graduatedList=[
(0, "Diğer"),
(1, "Lise"),
(2, "Lise (Öğrenci)"),
(3, "Ön Lisans"),
(4, "Ön Lisans (Öğrenci)"),
(5, "Lisans"),
(6, "Lisans (Öğrenci)"),
(7, "Yüksek Lisans"),
(8, "Yüksek Lisans (Öğrenci)"),
(9, "Doktora"),
(10, "Doktora (Öğrenci)")
]
def validate_digit_length(idName):
if not (idName.isdigit() and len(idName) == 11):
raise ValidationError('%(idName)s en az 11 karakter olmalıdır', params={'idName': idName}, )
name = models.CharField(max_length=20, verbose_name="Ad")
midName = models.CharField(max_length=20, verbose_name="Orta Ad", null=False, blank=True)
surName = models.CharField(max_length=20, verbose_name="Soy Ad")
university = models.IntegerField(choices=UniversityList.objects.get(),default=0, verbose_name="Son Mezun Olunan Üniversite")
graduated = models.IntegerField(choices=graduatedList, default=0, verbose_name="Tahsil Durumu")
def __str__(self):
return f"{self.name},{self.surName}"
class Meta:
db_table = "mainland2"
verbose_name_plural = "Ar-Ge Personeller"
Doing objects.get() like that will try to get 1 object from the database, but you've got 5 by the sounds of it.
Something like objects.first() would work, but also it's a bad idea to perform that operation on the database in the model like that. You should override forms to perform the database operation in the creation of the form.
So, keep the field on the model simple;
university = models.IntegerField(default=0, verbose_name="Son Mezun Olunan Üniversite")
Then setup the choices in any forms which use the model. An example of this would look like;
class Mainland2Form(forms.ModelForm):
""" Mainland2 form """
class Meta:
""" Setup the form """
model = Mainland2
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
unis = UniversityList.objects.values_list(
'id', 'name'
)
# Make sure we've got an empty choice to avoid people not using the field taking the first choice
uni_choices = \
[(None, '')] + [(u[0], u[1]) for u in list(unis)]
self.fields['university'].choices = uni_choices
You can then override the admin form for your admin class. Check out these docs;
https://docs.djangoproject.com/en/3.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.form
What you probably want though, given you're doing this in admin, is just a ForeignKey relationship. Django will then handle the choices for you.
And when it comes to FK relationships in admin, you should consider the additional overhead of having to select all the related objects in order to generate the select box.
If the related model has a lot of objects, you can reduce this database query by using raw_id_fields on your model admin.
For example;
class Mainland2Admin(admin.ModelAdmin):
raw_id_fields = ("university",)
https://docs.djangoproject.com/en/3.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.raw_id_fields

Django Multiple Choice Filter With Ranges

I am reading through django documentation for filters and came across the multiple choice filter.
class User(models.Model):
username = models.CharField(max_length=255)
first_name = SubCharField(max_length=100)
last_name = SubSubCharField(max_length=100)
status = models.IntegerField(choices=STATUS_CHOICES, default=0)
STATUS_CHOICES = (
(0, 'Regular'),
(1, 'Manager'),
(2, 'Admin'),
)
class F(FilterSet):
status = ChoiceFilter(choices=STATUS_CHOICES)
class Meta:
model = User
fields = ['status']
In my application I have a decimal field representing the price in my product model. I was wondering if there was a way I could use the multiple choice filter to select price ranges, e.g.,
(0-200, '$'),
(201-500, '$$'),
(501-1000, '$$$')
I am aware of the range filter but I need the functionality of the multiple choice filter and be able to select multiple ranges.
There isn't any standard behavior to extend here since you're trying to filter by multiple ranges. Your best bet is to use the method argument on a multiple choice filter to provide the custom behavior.
class F(django_filters.FilterSet):
price = MultipleChoiceFilter(choices=(('$': '$', ...)), method='filter_price')
def filter_price(self, queryset, name, value):
# value should be a list since it's multiple choice
for price in value:
if price == '$':
...
return ...

Django Model conditional relationship

Newbie question: Django + Postgres + PostGIS
I am trying to setup a Projects model in Django that needs to be conditionally related to a geometry model depending on its geometry type. the geometry types are : Points, Lines or Polygons. The question is how do I define this relationship in the Project Model so that I do not have to save the different geometry types in the same table ( Hence the 3 different geometry models)
=======================Here are my models ============================
PRJ_GEOM = (
(1, "point"),
(2, "line"),
(3, "polygon")
)
class Project(models.Model):
name = models.CharField(max_length=20)
project_geom_type = models.IntegerField(choices=PRJ_GEOM)
project_geometry = models.OneToOneField( ????) # I am stuck here - how do I express this conditional relationship which depends on project_geom_type
# Geometry Model
class Project_Point_Geom(models.Model):
project = models.OneToOne(Project, on_delete=models.CASCADE, related_name='project_point')
point = models.PointField()
class Project_Line_Geom(models.Model):
project = models.OneToOne(Project, on_delete=models.CASCADE, related_name='project_line')
line = models.LineStringField()
class Project_Polygon_Geom(models.Model):
project = models.OneToOne(Project, on_delete=models.CASCADE, related_name='project_polygon')
polygon = models.PolygonField()
Actually you only need one model. All geometry fields are derived from GeometryField so you can use it to store it's sub classes.
PRJ_GEOM = (
(1, "point"),
(2, "line"),
(3, "polygon")
)
class Project(models.Model):
name = models.CharField(max_length=20)
project_geom_type = models.IntegerField(choices=PRJ_GEOM)
project_geometry = models.GeometryField()
That is all! one model, one table instead of four which is much easier to maintain. And the data is slightly smaller because the relation field is eliminated.
Your Project model doesn't need the project_geometry fields. You only need to relate your different geometry models to the project using your OneToOne field. Django automatically creates reverse relationships for ForeignKey, ManyToMany and OneToOne relationships. Your classes would look something like this:
class Project(models.Model):
name = models.CharField(max_length=20)
class Point_Geo(models.Model):
project = models.OneToOne(Project) # truncated for example
point = models.PointField()
class Line_Geo(models.Model):
project = models.OneToOne(Project) # truncated for example
line = models.LineStringField()
class Polygon_Geo(models.Model):
project = models.OneToOne(Project) # truncated for example
polygon = models.PolygonField()
When you've got a Project instance you can walk back along the reverse relationship like this:
project = Project.objects.get(id=1)
point = project.point_geo.point
To query for all projects with point geometry you could query:
projects_with_points = Project.objects.exclude(point_geo=None)

Django queryset. Convert output to list

class Box(models.Model):
owner = models.ForeignKey(User, related_name='user', verbose_name='Owner')
name = models.CharField("Name", max_length=30)
items = models.ManyToManyField('Item', through='BoxItem', blank=True, null=True)
class BoxItem(models.Model):
item = models.ForeignKey('Item')
box = models.ForeignKey('Box')
quantity = models.IntegerField()
class Item(models.Model):
name = models.CharField("Name Item", max_length=30)
In [1]: from project.app.models import *
In [2]: b = Box.objects.get(owner=1)
In [3]: b.items_all()
Out[4]: [<Item: PC>, <Item: Notebook>]
How to convert this Output to list?
How to add to this list quantity next to the name of Item? (Example: PC - 3, Notebook- 5)
What about something like:
b = Box.objects.get(owner=1)
[('%s - %s' % (box_item.item.name, box_item.quantity)) for box_item in b.items_all()]
In line 4 it appears that the result of b.items_all() is actually a QuerySet; you can use any of the QuerySet's methods; for most purposes (including list access) I usually use the QuerySet directly.
In order to have quantity shown next to the name of Item at Python shell level you can use the __unicode__ method at Model level; this should be easy to achieve if you have a one-to-one relationship between Item and BoxItem; recall that this would result in an additional join each time the __unicode__ function is called.