Django admin admin_order_field with other table - django

How to sort by custom field in Django admin.
My database's tables are without any ForeignKey,
django framework design by related ship.
This model define:
class UserBaseInfo(BaseModel):
STATUS = [(0, 'not pass'), (1, 'pass')]
SEX = [(0, 'unset'), (1, 'male'), (2, 'female')]
parent_id = models.IntegerField(max_length=11, default=0)
level_id = models.IntegerField(max_length=11, default=1)
phone = models.BigIntegerField(max_length=15, null=True, blank=True, default=None)
nickname = models.CharField(max_length=100)
sex = models.IntegerField(null=False, blank=False, default=1, choices=SEX)
country = models.CharField(max_length=100, null=True, blank=True)
province = models.CharField(max_length=100, null=True, blank=True)
city = models.CharField(max_length=100, null=True, blank=True)
headimgurl = models.CharField(max_length=255, null=True, blank=True)
status = models.IntegerField(max_length=3, default=0)
updated_time = models.BigIntegerField(max_length=18, null=True, blank=True)
class Meta:
db_table = 'user_base_info'
ordering = ('-created_time', '-updated_time')
def save(self, force_insert=False, force_update=False, using=None,
update_fields=None):
initial = False
if not self.id:
initial = True
super(UserBaseInfo, self).save(force_insert=force_insert, force_update=force_update, using=using,
update_fields=update_fields)
if initial:
Wallet(user_id=self.id, money=1000).save()
class Wallet(models.Model):
user_id = models.BigIntegerField(max_length=18, primary_key=True, null=False, blank=False, verbose_name=_('UserId'))
money = models.FloatField(null=False, blank=False)
class Meta:
db_table = 'wallet'
This admin
class UserBaseInfoAdmin(CSVAdmin):
list_display = ('nickname', 'avatar', 'level_id', 'parent', 'income', 'sex', 'country', 'province', 'city')
list_filter = ('nickname', 'level_id', 'sex', ('created_time', DateFieldListFilter), ('updated_time', DateFieldListFilter))
search_fields = ('nickname', 'level_id', 'sex', 'created_time', 'updated_time')
list_display_links = ('level_id',)
readonly_fields = ('nickname', 'level_id', 'sex', 'country', 'province', 'city', 'headimgurl',
'language', 'openid', 'privilege', 'created_time', 'updated_time')
list_per_page = 20
list_max_show_all = 20
def avatar(self, data):
return format_html('<img src="%s" height="50px" style="border-radius:50px"/>' % data.headimgurl)
def parent(self, data):
user = UserBaseInfo.objects.filter(pk=data.parent_id).first()
return user.nickname if user else ''
parent.allow_tags = True
parent.admin_order_field = 'parent_id'
def income(self, data):
wallet = Wallet.objects.filter(user_id=data.id).first()
if wallet:
return wallet.money / 100
income.admin_order_field = 'wallet__money'
I want to order by wallet's money, but I don't how to do next;

Related

association user with forms

I'm making something like this: admin creates form manually, and user is automatically created with this form.
But I need to add association that form to a new automatically created user, that's where I'm stuck. How can I make user auto registration to associate that form
I need this because I want to then to show 'filtered, created' form by user.
Views.py
def create_driver_view(request):
if request.method == "POST":
add_driver = DriverForm(request.POST)
add_driver_files = request.FILES.getlist("file")
if add_driver.is_valid():
email = request.POST['email']
usern = 'test'
passw = 'test'
user = User.objects.create_user(email = email, username = usern, password = passw)
user.save()
f = add_driver.save(commit=False)
f.user = request.user
f.save()
for i in add_driver_files:
DriversFiles.objects.create(driver_files=f, file=i)
return redirect('drivers:list_driver')
else:
print(add_driver.errors)
else:
add_driver = DriverForm()
add_driver_files = DriverFormUpload()
return render(request, "drivers/add.html", {"add_driver": add_driver, "add_driver_files": add_driver_files})
Forms.py
class DriverForm(forms.ModelForm):
class Meta:
model = Drivers
fields = [
'full_name',
'phone_number',
'email',
'address',
'country',
'state',
'city',
'zip',
'birth_date',
'license_no',
'license_exp_date',
'last_medical',
'next_medical',
'last_drug_test',
'next_drug_test',
'status',
]
class DriverFormUpload(forms.ModelForm):
class Meta:
model = DriversFiles
fields = [
'file',
]
widget = {
'file': forms.ClearableFileInput(attrs={'multiple': True}),
}
Models.py
STATUS = ((0, 'Inactive'), (1, 'Active'))
class Drivers(models.Model):
full_name = models.CharField(max_length=50, default=None)
phone_number = models.CharField(max_length=50, default=None)
email = models.EmailField(unique=True,max_length=255, default=None)
address = models.CharField(max_length=70, default=None)
country = models.CharField(max_length=50, default=None)
state = models.CharField(max_length=50, default=None)
city = models.CharField(max_length=50, default=None)
zip = models.CharField(max_length=50, default=None)
birth_date = models.DateField(default=None)
license_no = models.IntegerField(default=None)
license_exp_date = models.DateField(default=None)
last_medical = models.DateField(default='', blank=True, null=True)
next_medical = models.DateField(default='', blank=True, null=True)
last_drug_test = models.DateField(default='', blank=True, null=True)
next_drug_test = models.DateField(default='', blank=True, null=True)
date_created = models.DateTimeField(auto_now_add=True)
status = models.IntegerField(choices=STATUS, default=1)
class DriversFiles(models.Model):
file = models.FileField(upload_to="media/", blank=True, null=True)
driver_files = models.ForeignKey('Drivers', on_delete=models.CASCADE, default=None, null=True)

django slick report and nested categories

I am using in django the following models.py:
class Expense(models.Model):
name = models.CharField(max_length=50)
date = models.DateField(unique=False, blank=False)
slug = models.SlugField(unique=True, null=True, default='')
price = models.DecimalField(default=0.0, blank=True, max_digits = 20, decimal_places = 2)
category = models.ForeignKey(
'Category',
related_name="Expense",
on_delete=models.CASCADE
)
account = models.ForeignKey(Account, on_delete=models.CASCADE, verbose_name=u"Account", help_text=u"account")
def __str__(self):
return '{},{},{}'.format(self.name, self.date, self.price)
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Expense,self).save(*args, **kwargs)
def get_absolute_url(self):
return self.slug
class Category(MPTTModel):
name = models.CharField(max_length=200)
slug = models.SlugField(unique=True, null=True, default='')
parent = TreeForeignKey(
'self',
blank=True,
null=True,
related_name='child',
on_delete=models.CASCADE
)
class Meta:
unique_together = ('slug', 'parent',)
verbose_name_plural = "categories"
def __str__(self):
full_path = [self.name]
k = self.parent
while k is not None:
full_path.append(k.name)
k = k.parent
return ' -> '.join(full_path[::-1])
The TreeForeignKey allows me to define nested categories, such as Home -> Electricity and so on.
I am using the following Slick Report view.py:
class TotalExpenses(SlickReportView):
report_model = Expense
date_field = 'date'
group_by = 'category'
columns = ['name', SlickReportField.create(method=Sum, field='price', name='price__sum', verbose_name=('Total category $'))]
charts_settings = [
{
'type': 'bar',
'data_source': 'price__sum',
'title_source': 'name',
},
]
It works but I would like to sum only level 1 categories. Do you know how this might be possible?

DRF post request multiple inner serializers

i have three models named Smoker,Switch,Survey i have smoker as foreign key in Switch model and switch as foreign key in Survey model
class Smoker(models.Model):
first_name = models.CharField(max_length=50, blank=True, null=True)
last_name = models.CharField(max_length=50, blank=True, null=True)
mobile = models.IntegerField(null=True, blank=True)
gender = models.BooleanField(blank=True, null=True)
age = models.ForeignKey(Age,models.DO_NOTHING,blank=True, null=True)
occupation = models.ForeignKey(Occupation, models.DO_NOTHING, blank=True, null=True)
class Switch(models.Model):
time = models.TimeField(blank=True, null=True)
count_outers = models.IntegerField(blank=True, null=True)
count_packs = models.IntegerField(blank=True, null=True)
smoker = models.ForeignKey(Smoker, models.DO_NOTHING, blank=True, null=True)
new_brand = models.ForeignKey(NewBrand, models.DO_NOTHING, blank=True, null=True)
new_sku = models.ForeignKey(NewSku, models.DO_NOTHING, blank=True, null=True)
# def __str__(self):
# return self.time.strftime("%H:%M")
class Survey(models.Model):
user = models.ForeignKey(User, models.DO_NOTHING, blank=True, null=True)
date = models.DateField(null=True, blank=True)
bool_switch = models.BooleanField(null=True, blank=True)
reason = models.ForeignKey(Reason, models.DO_NOTHING, null=True, blank=True)
shift = models.ForeignKey(ShiftingTime, models.DO_NOTHING, null=True, blank=True)
current_brand = models.ForeignKey(CurrentBrand, models.DO_NOTHING, null=True, blank=True)
current_sku = models.ForeignKey(CurrentSku, models.DO_NOTHING, null=True, blank=True)
pos = models.ForeignKey(Pos, models.DO_NOTHING, null=True, blank=True)
switch = models.ForeignKey(Switch, models.DO_NOTHING, null=True, blank=True)
and here i have my serializers:
class SmokerSerializer(serializers.ModelSerializer):
class Meta:
model = Smoker
fields = '__all__'
class SwitchSerializer(serializers.ModelSerializer):
smoker = SmokerSerializer()
class Meta:
model = Switch
fields = '__all__'
def create(self, validated_data):
smoker_data = validated_data.pop('smoker', None)
if smoker_data:
smoker = Smoker.objects.create(**smoker_data)
validated_data['smoker'] = smoker
return Switch.objects.create(**validated_data)
class SurveySerializer(serializers.ModelSerializer):
switch = SwitchSerializer()
class Meta:
model = Survey
fields = '__all__'
def create(self, validated_data):
switch_data = validated_data.pop('switch', None)
if switch_data:
switch = Switch.objects.create(**switch_data)
validated_data['switch'] = switch
return Survey.objects.create(**validated_data)
and i make a generic for for Creating and listing all the survey
class SurveyCreateAPIView(generics.ListCreateAPIView):
def get_queryset(self):
return Survey.objects.all()
serializer_class = SurveySerializer
for each displayed survey i have to display switch data related to it and inside the switch object i need to display the smoker object inside it so each survey object must look like this
{
"id": 11,
"switch": {
"id": 12,
"smoker": {
"firstname":"sami",
"lastname:"hamad",
"mobile":"7983832",
"gender":"0",
"age":"2",
"occupation":"2"
},
"time": null,
"count_outers": 5,
"count_packs": 7,
"new_brand": 2,
"new_sku": 2
},
"date": "2018-12-08",
"bool_switch": true,
"user": 7,
"reason": 3,
"shift": 2,
"current_brand": 6,
"current_sku": 4,
"pos": 2
},
but when i make a POST request it is giving me this error
ValueError at /api/v2/surveysync/ Cannot assign
"OrderedDict([('first_name', 'aline'), ('last_name', 'youssef'),
('mobile', 7488483), ('gender', False), ('age', ),
('occupation', )])": "Switch.smoker" must be
a "Smoker" instance.
so please help and thank you so much!
You're going along the right path but you're saving the switch objects manually instead of allowing the SwitchSerializer do it for you. Same thing with create method in switch serializer. It should be this way:
class SmokerSerializer(serializers.ModelSerializer):
class Meta:
model = Smoker
fields = '__all__'
class SwitchSerializer(serializers.ModelSerializer):
smoker = SmokerSerializer()
class Meta:
model = Switch
fields = '__all__'
def create(self, validated_data):
smoker_data = validated_data.pop('smoker', None)
if smoker_data:
serializer = SmokerSerializer(data=smoker_data, context=self.context)
if serializer.is_valid():
validated_data['smoker'] = serializer.save()
return super().create(validated_data)
class SurveySerializer(serializers.ModelSerializer):
switch = SwitchSerializer()
class Meta:
model = Survey
fields = '__all__'
def create(self, validated_data):
switch_data = validated_data.pop('switch', None)
if switch_data:
serializer = SwitchSerializer(data=switch_data, context=self.context)
if serializer.is_valid():
validated_data['switch'] = serializer.save()
return super().create(validated_data)
In SwitchSerializer you defined the create function as a method of the inner Meta class and not as a member of SwitchSerializer class. Try this
class SwitchSerializer(serializers.ModelSerializer):
smoker = SmokerSerializer()
class Meta:
model = Switch
fields = '__all__'
def create(self, validated_data):
smoker_data = validated_data.pop('smoker', None)
if smoker_data:
smoker = Smoker.objects.create(**smoker_data)
validated_data['smoker'] = smoker
return Switch.objects.create(**validated_data)

Django rest framework - cant serialize query set

I try to serialize query set
def do(self):
reservations = Reservation.objects.all()
serializer = ReservationSerializer(data=reservations, many=True)
if serializer.is_valid():
encoded_data = json.dumps(serializer.data)
r = requests.post('http://httpbin.org/post', headers={'Content-Type': 'application/json'}, data=encoded_data)
print(r.text)
else:
print(serializer.errors)
And I always get error of
{u'non_field_errors': [u'Expected a list of items but got type "QuerySet".']}
I tried to use values() on query set, and then convert to list, but this way I get objects without nested models
model
class Reservation(models.Model):
start = models.DateField(verbose_name='Заезд', auto_now=False, auto_now_add=False, blank=False)
end = models.DateField(verbose_name='Выезд', auto_now=False, auto_now_add=False, blank=False)
check_in_time = models.TimeField(verbose_name='Время заезда', blank=False)
check_out_time = models.TimeField(verbose_name='Время выезда', blank=False)
has_refund = models.BooleanField(verbose_name='Возвратная бронь', default=True)
payed = models.BooleanField(verbose_name='Оплачено', default=False)
reserved_days = models.ManyToManyField(Day, blank=False)
additional_services = models.ManyToManyField(AdditionalService)
guest_name = models.CharField(verbose_name='Имя гостя', max_length=200, blank=True)
reservation_number = models.CharField(verbose_name='Номер брони', max_length=200, blank=True)
class AdditionalService(models.Model):
payment_date = models.CharField(verbose_name='Дата оплаты', max_length=200, blank=True)
payment_type = models.CharField(verbose_name='Форма оплаты', max_length=200, blank=False)
service = models.CharField(verbose_name='Услуга', max_length=200, blank=False)
quantity = models.IntegerField(blank=False)
price = models.FloatField(blank=False)
class Day(models.Model):
date = models.DateField(auto_now=False, auto_now_add=False)
price = models.FloatField()
payment_method = models.CharField(max_length = 200, blank=True)
payment_date = models.CharField(max_length=200, blank=True)
room = models.ForeignKey(Room, null=True, blank=True, verbose_name='Номер', on_delete=models.CASCADE)
class Room(models.Model):
name = models.CharField(max_length = 200, null=True)
id = models.AutoField(primary_key=True)
room_id = models.CharField(max_length = 200, null=False)
def __unicode__(self):
return self.name
serializers
class ReservationSerializer(serializers.ModelSerializer):
reserved_days = DaySerializer(many=True)
additional_services = AdditionalServicesSerializer(many=True)
class Meta:
model = Reservation
fields = [
'start',
'end',
'check_in_time',
'check_out_time',
'reserved_days',
'additional_services',
'has_refund',
'payed',
'guest_name',
'reservation_number',
]
class DaySerializer(serializers.ModelSerializer):
room = RoomSerializer()
class Meta:
model = Day
fields = [
'date',
'price',
'payment_method',
'payment_date',
'room',
]
class AdditionalServicesSerializer(serializers.ModelSerializer):
class Meta:
model = AdditionalService
fields = [
'payment_date',
'payment_type',
'service',
'quantity',
'price',
]
class RoomSerializer(serializers.ModelSerializer):
class Meta:
model = Room
fields = [
'room_id',
]
For serialization you don't need to use data keyword, just pass queryset as first positional argument:
serializer = ReservationSerializer(reservations, many=True)
return serializer.data

How can I override choices of abstract class?

I have AbstractProfile model with predefined PRIVACY_CHOICES:
class AbstractProfile(models.Model):
PRIVACY_CHOICES = (
(1, _('all')),
(2, _('no one')),
)
title = models.CharField(_('title'), max_length=30)
info = models.TextField(_('information'), max_length=500, blank=True)
info_privacy = models.IntegerField(_('show information to'), default=1, choices=PRIVACY_CHOICES)
city = models.CharField(_('location'), max_length=30, blank=True)
city_privacy = models.IntegerField(_('show location to'), default=1, choices=PRIVACY_CHOICES)
address = models.CharField(_('address'), max_length=30, blank=True)
address_privacy = models.IntegerField(_('show address to'), default=1, choices=PRIVACY_CHOICES)
class Meta:
abstract = True
class UserProfile(AbstractProfile):
PRIVACY_CHOICES = (
(1, _('all')),
(2, _('friends')),
(3, _('friends of friends')),
(4, _('only me')),
)
title = None
first_name = models.CharField(_('first name'), max_length=30, blank=True)
last_name = models.CharField(_('last name'), max_length=30, blank=True)
names_privacy = models.IntegerField(_('show names to'), default=1, choices=PRIVACY_CHOICES)
birth_date = models.DateField(_('birth date'), null=True, blank=True)
birth_date_privacy = models.IntegerField(_('show birth date to'), default=1, choices=PRIVACY_CHOICES)
avatar = models.ImageField(upload_to='users/avatar', null=True, blank=True)
UserProfile should have fields from AbstractProfile, but with its own PRIVACY_CHOICES. In the current realisation PRIVACY_CHOICES of UserProfile does not override PRIVACY_CHOICES of AbstractProfile. How is it possible to solve? In the future could be other models, which also should have its own PRIVACY_CHOICES
I use Django 1.10
Found solution.
models.py:
class AbstractProfile(models.Model):
PRIVACY_CHOICES = (
(1, _('all')),
(2, _('no one')),
)
title = models.CharField(_('title'), max_length=30)
info = models.TextField(_('information'), max_length=500, blank=True)
info_privacy = models.IntegerField(_('show information to'), default=1, choices=PRIVACY_CHOICES)
city = models.CharField(_('location'), max_length=30, blank=True)
city_privacy = models.IntegerField(_('show location to'), default=1, choices=PRIVACY_CHOICES)
address = models.CharField(_('address'), max_length=30, blank=True)
address_privacy = models.IntegerField(_('show address to'), default=1, choices=PRIVACY_CHOICES)
class Meta:
abstract = True
class UserProfile(AbstractProfile):
PRIVACY_CHOICES = (
(1, _('all')),
(2, _('friends')),
(3, _('friends of friends')),
(4, _('only me')),
)
# NEW PIECE OF CODE
def __init__(self, *args, **kwargs):
def get_class_attrs(cls):
return re.findall(r'\w+(?=[,\)])', cls.__dict__['__doc__'])
super(UserProfile, self).__init__(*args, **kwargs)
all_fields = get_class_attrs(UserProfile)
for each_field in all_fields:
# all fields with '_privacy' in the name have 'choice' option
if '_privacy' in each_field:
self._meta.get_field(each_field).choices = self.PRIVACY_CHOICES
default_privacy_choice = self.PRIVACY_CHOICES[0][0]
if self._meta.get_field(each_field).default != default_privacy_choice:
self._meta.get_field(each_field).default = default_privacy_choice
# END OF NEW PIECE OF CODE
title = None
first_name = models.CharField(_('first name'), max_length=30, blank=True)
last_name = models.CharField(_('last name'), max_length=30, blank=True)
names_privacy = models.IntegerField(_('show names to'), default=1, choices=PRIVACY_CHOICES)
birth_date = models.DateField(_('birth date'), null=True, blank=True)
birth_date_privacy = models.IntegerField(_('show birth date to'), default=1, choices=PRIVACY_CHOICES)
avatar = models.ImageField(upload_to='users/avatar', null=True, blank=True)
class CompanyProfile(AbstractProfile):
pass
class OneMoreClass(AbstractProfile):
pass
Also is it necessary to modify forms.py:
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile() # old_version was: model = UserProfile
fields = ('title',
'first_name', 'last_name', 'names_privacy',
'birth_date', 'birth_date_privacy',
'info', 'info_privacy',
'city', 'city_privacy', 'address', 'address_privacy',
'avatar',)
Unmodified form takes choices from Abstract class. Now it is not required to repeat the same fields in different classes. If all classes have its own versions of choices, then method def __init__ can be copied to those classes with proper modifications (at least to change the class name), or even can be made as a separate function, but this is another story.