Django: Cannot Update the Value of IntegerField - django

I have an IntegerField in my model and I try to update it in the admin page. No matter what value I input (e.g. 100, 200), the value is restored to 0 after saving it.
models.py
class inputform(models.Model):
name = models.CharField('Name', max_length=40)
gender_choices = (
(0,'Female'), (1,'Male'),
)
gender = models.SmallIntegerField('Gender', choices=gender_choices, blank=True)
age = models.IntegerField('Age', blank=True, null=True)
email = models.CharField('email', max_length=64, blank=True)
live_choices = (
(0,'Other'), (1,'Live alone'), (2,'Live with family'),
)
live = models.SmallIntegerField('Living Status', choices=live_choices, blank=True)
admin.py
from django.contrib import admin
from myApp.models import inputForm
class inputForm(admin.ModelAdmin):
list_display = ('id','name', 'age', 'gender')
I have tried change the value via SQL in the database directly and it updated successfully. However, when I read it in the admin page and saved it without any change, the value restore to 0.
Is there any wrong with my code? Thanks!

Related

Django model select between two columns/fields?

I have a Slider module that i want to include items from movies_movie and shows_show table. An item can either be a show or movie. How do i make user select between movie and show? Currently i have columns for movie and show but how do i force user to select between the two?
also title_en is a column in movie or tv show tables. So the title of the movie/show selected should display in row after save.
class Slider_items(models.Model):
order = models.IntegerField(max_length=3, blank=True)
movie = models.ForeignKey('movies.movie', on_delete=models.CASCADE, blank=True)
show = models.ForeignKey('shows.show', on_delete=models.CASCADE, blank=True)
def __str__(self):
return self.title_en
class Meta:
verbose_name = "Slider Items Module"
verbose_name_plural = "Slider Item Module"
Also if a show is selected and a movie isn't, how do i know title_en will be taken from show and not movie?
I think you can do something like this:
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
class Slider_items(models.Model):
order = models.IntegerField(max_length=3, blank=True)
# don't forget to add null=True to both fields
movie = models.ForeignKey('movies.movie', on_delete=models.CASCADE, blank=True, null=True)
show = models.ForeignKey('shows.show', on_delete=models.CASCADE, blank=True, null=True)
# see docs, https://docs.djangoproject.com/en/3.2/ref/models/instances/#django.db.models.Model.clean
def clean(self):
if self.movie and self.show:
raise ValidationError({'movie': _('You can't select both types at the same time')})
elif not self.movie and not self.show:
raise ValidationError({'movie': _('You must select one type')})
def __str__(self):
return self.movie.title_en if self.movie else self.show.title_en
class Meta:
verbose_name = "Slider Items Module"
verbose_name_plural = "Slider Item Module"
You may consider using django contenttypes.
Imagine in the future, you have not just Movie, Show, but have new Class such as Book, Podcase, it might not be a good idea to keep adding new foreignkey to your Slider Model.
I have not used contenttype before, so I am referencing this SO answer.
(using python 3.6, django 3.2)
models.py
from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
class Movie(models.Model):
title = models.CharField(max_length=50)
director = models.CharField(max_length=50)
class Show(models.Model):
title = models.CharField(max_length=50)
date = models.DateField()
class Slider(models.Model):
order = models.IntegerField(max_length=3, blank=True)
choices = models.Q(model='movie') | models.Q(model='show')
selection_type = models.ForeignKey(
ContentType, limit_choices_to=choices,
on_delete=models.CASCADE)
selection_id = models.PositiveIntegerField()
selection = GenericForeignKey('selection_type', 'selection_id')
def __str__(self):
return self.selection.title
admin.py
#admin.register(Slider)
class SliderAdmin(admin.ModelAdmin):
pass
at django shell, the following is valid.
movie = Movie.objects.create(title='movie 1', director='ben')
show = Show.objects.create(title='show 1', date='2021-01-01')
s1 = Slider.objects.create(selection=movie, order=1)
s2 = Slider.objects.create(selection=show, order=2)
However, using limit_choices_to only restrict the choices in admin page, and there is no constraint at database level. i.e. the following are actually legal.
place = Place.objects.create(name='home')
s3 = Slider.objects.create(selection=s3, order=3)
I have not found a fix for this issue yet. Maybe doing some validation in save method is a way (see the comments under this).

Automatically search all fields for all models in django admin

I want to be able to search all models for all fields in Django admin, without having to setup ModelAdmin and searchfields individually.
example:
I have all my models in model.py:
# This is an auto-generated Django model module.
from django.db import models
class Diagnosis(models.Model):
id = models.BigAutoField(primary_key=True)
code = models.CharField(max_length=255)
starting_node = models.ForeignKey('Node', models.DO_NOTHING, blank=True, null=True)
class Meta:
managed = False
db_table = 'diagnosis'
def __str__(self):
return 'Diag #' + str(self.id) + ' - ' + self.code
class DiagnosisHistory(models.Model):
id = models.IntegerField(primary_key=True)
title = models.CharField(max_length=255, blank=True, null=True)
date = models.DateTimeField(blank=True, null=True)
id_user = models.TextField(blank=True, null=True)
report = models.TextField(blank=True, null=True)
json_report = models.TextField(blank=True, null=True)
vin = models.CharField(max_length=20, blank=True, null=True)
class Meta:
managed = False
db_table = 'diagnosis_history'
# and so on
and the admin.py where I register the models:
from django.contrib import admin
from . import models
# Do not care. Register everything
for cls in [cls for name, cls in models.__dict__.items() if isinstance(cls, type)]:
admin.site.register(cls)
I don't want to run through each Model and manually create a ModelAdmin with each field
This is the solution I came up with:
from django.contrib import admin
from django.db import models as django_models
from . import models
relationship_fields = (django_models.ManyToManyField, django_models.ForeignKey, django_models.OneToOneField)
for cls in [cls for name, cls in models.__dict__.items() if isinstance(cls, type)]:
meta_fields = [field.name for field in cls._meta.local_fields if not isinstance(field, relationship_fields)]
class Admin(admin.ModelAdmin):
search_fields = meta_fields
admin.site.register(cls, Admin)
Note: registering all fields will fail since some are relationships. using cls._meta.local_fields exclude inferred relationships but you also need to exclude fields such as foreign keys defined in your model. Thus, we filter with isinstance(field, relationship_fields)
Note 2: I should probably use get_fields since local_fields seems to be private API (see https://docs.djangoproject.com/en/3.1/ref/models/meta/)
class MyModelAdmin(admin.ModelAdmin):
# ...
search_fields = [field.name for field in MyModel._meta.fields]
# ...

after I created multiple models in my django app for the restframwork I start getting more errs

I created a single model django project then I added tow more models then I got this err
RecursionError at /elements/
maximum recursion depth exceeded while calling a Python object
then I reinstalled some packages like djangorestframwork-recursion, then I got this err
Error at /
Incorrect padding
Request Method: GET
Request URL: http://127.0.0.1:8000/
Django Version: 3.0.8
Exception Type: Error
Exception Value:
Incorrect padding
Exception Location: //anaconda3/lib/python3.7/base64.py in b64decode, line 87
Python Executable: //anaconda3/bin/python
Python Version: 3.7.3
Python Path:
['/Users/apple/Desktop/Trying to clone notionso note taking app with django '
'and reac1/backend/restapi',
'//anaconda3/lib/python37.zip',
'//anaconda3/lib/python3.7',
'//anaconda3/lib/python3.7/lib-dynload',
'/Users/apple/.local/lib/python3.7/site-packages',
'//anaconda3/lib/python3.7/site-packages',
'//anaconda3/lib/python3.7/site-packages/aeosa']
Server time: Fri, 7 Aug 2020 06:59:57 +0000
also when I ran python manage.py makemigrations i got
You are trying to change the nullable field 'text' on components to non-nullable without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
2) Ignore for now, and let me handle existing rows with NULL myself (e.g. because you added a RunPython or RunSQL operation to handle NULL values in a previous data migration)
3) Quit, and let me add a default in models.py
Select an option:
what is the problem with the nullable field 'text' (also I change every null=Flase to null=True i got the same err.
models.py
# this is a recursive model
from django.db import models
class elements(models.Model):
tag = models.CharField(blank=True, null=True, max_length=20)
text = models.TextField(blank=True, null=False)
src = models.URLField(blank=True, null=True)
# problem: styles replace spaces with slashes (/)
# I tried: json field but did'nt work.
style = models.TextField(blank=True, null=True)
main = models.ForeignKey(
'self', null=True, blank=True, related_name="sub", on_delete=models.PROTECT)
class styles(models.Model):
name = models.TextField(blank=True, null=True, max_length=50)
style = models.TextField(blank=True, null=True)
main = models.ForeignKey(
'self', null=True, blank=True, related_name="sub", on_delete=models.PROTECT)
class components(models.Model):
name = models.TextField(blank=True, null=True, max_length=50)
tag = models.CharField(blank=True, null=True, max_length=20)
text = models.TextField(blank=True, null=False)
src = models.URLField(blank=True, null=True)
style = models.TextField(blank=True, null=True)
main = models.ForeignKey(
'self', null=True, blank=True, related_name="sub", on_delete=models.PROTECT)
serialzers.py
from rest_framework import serializers
from models.models import elements, styles, components
from rest_framework_recursive.fields import RecursiveField
class elementsSerializer(serializers.ModelSerializer):
sub = RecursiveField(many=True, required=False)
class Meta:
model = elements
fields = ('id', 'tag', 'text', 'src', 'style', 'main', 'sub')
class stylesSerializer(serializers.ModelSerializer):
sub = RecursiveField(many=True, required=False)
class Meta:
model = styles
fields = ('id', 'name', 'style', 'main', 'sub')
class componentsSerializer(serializers.ModelSerializer):
sub = RecursiveField(many=True, required=False)
class Meta:
model = components
fields = ('id', 'name', 'tag', 'text', 'src', 'style', 'main', 'sub')
view.py
from models.models import elements, styles, components
from .serializers import elementsSerializer, stylesSerializer, componentsSerializer
from rest_framework import viewsets
class elementsVeiwSet(viewsets.ModelViewSet):
serializer_class = elementsSerializer
queryset = elements.objects.all()
class stylesVeiwSet(viewsets.ModelViewSet):
serializer_class = stylesSerializer
queryset = styles.objects.all()
class componentsVeiwSet(viewsets.ModelViewSet):
serializer_class = componentsSerializer
queryset = components.objects.all()
urls.py
from models.models import elements, styles, components
from .serializers import elementsSerializer, stylesSerializer, componentsSerializer
from rest_framework import viewsets
class elementsVeiwSet(viewsets.ModelViewSet):
serializer_class = elementsSerializer
queryset = elements.objects.all()
class stylesVeiwSet(viewsets.ModelViewSet):
serializer_class = stylesSerializer
queryset = styles.objects.all()
class componentsVeiwSet(viewsets.ModelViewSet):
serializer_class = componentsSerializer
queryset = components.objects.all()
1)
I am not sure why you have this field in each of your models
main = models.ForeignKey('self', null=True, blank=True, related_name="sub", on_delete=models.PROTECT)
I think this is the reason for your recursion problem. Try removing it.
2) Regarding your problem with the nullable Field text it is because you did not provide a default value (you have to do that because you did not allow it to be Null). You do it like that:
text = models.TextField(blank=True, null=False, default='')

Django Admin custom foreign key select box

I want to customize Django admin select box and show thumbnail in the select box next to the image title
I have a class called Image and another class called News, that has a foreign key to the Image.
Note: I use Django jet as admin template.
class Image(models.Model):
alternate = models.CharField(
verbose_name=_('Alternate'),
max_length=255,
null=True,
blank=True
)
title = models.CharField(
verbose_name=_('Title'),
max_length=255,
null=True,
blank=True
)
artist = models.ManyToManyField(
'Artist',
verbose_name=_('Artist'),
blank=True
)
image = models.ImageField()
def __str__(self):
return "({}) {}".format(self.pk, self.title)
class Meta:
verbose_name = _('Image Attachment')
verbose_name_plural = _('Image Attachments')
#staticmethod
def autocomplete_search_fields():
return 'title',
class News(BaseModel):
title = models.CharField(
verbose_name=_('Title'),
max_length=255,
null=True,
blank=True
)
summery = RichTextField(
verbose_name=_('Summery'),
null=True,
blank=True,
)
main_image = models.ForeignKey(
Image,
verbose_name=_('Main Image'),
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name='images'
)
Now I want to show the thumbnail of the image in choices in Django admin when I want to add news.
Now my select box look like this
You will need to create a custom widget that inherits from Select, the most important part it seems will be setting the option_template_name to be a template that you create to show the image. Since you are using something other than the base Django Admin, you may want to look into extending the widgets in that Library.
Something along the lines of:
class SelectWithImage(Select):
...
option_template_name = 'myapp/forms/widgets/select_option_with_image.html'
...
Then adjust the admin formfield_overrides for the News model in your admin.py as described here and you should be good to go!
This step will look something like this:
from django.contrib import admin
from django.db import models
# Import our custom widget and our model from where they're defined
from myapp.models import News
from myapp.widgets import SelectWithImage
class NewsAdmin(admin.ModelAdmin):
formfield_overrides = {
models.ForeignKey: {'widget': SelectWithImage},
}

datefield may not be NULL

I am trying to create an update form from User.profile. But when i load the url i get an error:
IntegrityError at /accounts/profile/
userprofile_userprofile.dob may not be NULL
Even if I give the 'dob' as null=True, I am getting the same error. But from the admin, I can add UserProfiles. Where am I doing wrong? Please help.
models.py:
from django.db import models
from django.contrib.auth.models import User
from time import time
def get_upload_file_name(instance, filename):
return "uploaded_files/profile/%s_%s" %(str(time()).replace('.','_'), filename)
class UserProfile(models.Model):
GENDER = (
("M", "Male"),
("F", "Female"),
("O", "Other"),
)
RELATIONSHIP = (
("S", "Single"),
("M", "Married"),
("D", "Divorced"),
)
user = models.OneToOneField(User)
image = models.ImageField(upload_to=get_upload_file_name)
gender = models.CharField(max_length=1, choices=GENDER)
dob = models.DateField('date of birth', blank=True, null=True)
about = models.TextField()
occupation = models.CharField(max_length=30)
state = models.CharField(max_length=20)
t_address = models.CharField(max_length=30)
p_address = models.CharField(max_length=30)
relationship = models.CharField(max_length=1, choices=RELATIONSHIP)
User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])
forms.py:
from django import forms
from models import UserProfile
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('image', 'gender', 'dob', 'about', 'state', 't_address', 'p_address', 'relationship')
You have likely already run syncdb prior to making your edits (see karthikr's comment). You can either delete the table and rerun syncdb or you can edit the table using SQL:
ALTER TABLE user_profile ALTER COLUMN dob DROP NOT NULL;
I don't think you are able to update existing tables with syncdb
In order for this to work you should either manually edit the database using SQL or whatever GUI you have available or you can drop the table(s) that you want to edit, update your models.py with null=True/blank=Trueand then run syncdb.