I've a model that I know is recording correctly the values in DataBase, but it is not showing them correctly in Admin Panel.
I know it's saving this fields correctly because:
1.- I can Query the model in Shell and see the values correctly.
2.- I'm using this model's fields to create another model, and this other model saves correctly and SHOWs correctly it's fields in Admin Panel.
What could be wrong?
Shell:
>>> SizeQuantity.objects.get(pk=9)
<SizeQuantity: variante_125 por cantidad_200>
>>> SizeQuantity.objects.get(pk=9).size
'variante_125'
>>> SizeQuantity.objects.get(pk=9).quantity
'cantidad_200'
What I see in AdminPanel:
This is my other model that uses values from SizeQuantiy:
I was expecting to render the Size and Quantity fields like this for my SizeQuantity model:
from .models import Cart, SizeQuantity
# Register your models here.
admin.site.register(Cart)
admin.site.register(SizeQuantity)
models.py:
class SizeQuantity(models.Model):
cart = models.ForeignKey(Cart, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
size = models.CharField(max_length=20, choices=TAMANIOS)
quantity = models.CharField(max_length=20, choices=CANTIDADES)
image = models.ImageField(upload_to='images', blank=True, null=True)
comment = models.CharField(max_length=200, blank=True, null=True, default='')
uploaded_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.id) + " - " + str(self.size) + " por " + str(self.quantity)
#property
def image_filename(self):
return self.image.url.split('/')[-1]
Probably Django can't render your fields correctly because mentioned values are not included in fields choices (TAMANIOS CANTIDADES)
Your field above ('variante_125', 'cantidad_200') is not in your valid CHOICES.
You can add any char for size and quantity fields although you don't write the values in CHOICES. But you can't use the choices such as get_FOO_display. It's helpful to check docs here (https://docs.djangoproject.com/en/2.1/ref/models/fields/#choices).
You should check TAMANIOS, CANTIDADES choices that have those values.
Related
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).
I have a Profile model:
from django.contrib.auth.models import User
class Profile(models.Model):
first_name = models.CharField(max_length=100, blank=True)
last_name = models.CharField(max_length=100, blank=True)
user = models.OneToOneField(User, on_delete=models.CASCADE)
birthday = models.DateField(null=True, blank=True)
bio = models.TextField(blank=True, max_length=1000)
location = models.CharField(max_length=100, blank=True)
...
And a search contacts view:
class SearchContactsView(ListView):
model = Profile
template_name = 'users/contact_search.html'
context_object_name = 'qs'
def get_queryset(self):
q1 = self.request.GET.get('contact_name')
q2 = self.request.GET.get('contact_location')
if q1 or q2:
return Profile.objects.filter(Q(first_name__icontains=q1) |
Q(last_name__icontains=q1),
location__icontains=q2)
return Profile.objects.all()
It is working fine but I would like to be able to search for contacts via the user field as well. Does anyone know a way to do that?
EDIT my user's username's are created by them when they sign up to the site and are currently uneditable. They are displayed on the admin page via a dropdown since they are a OneToOneField. I think my issue is that django recognises them only as an IntegerField('pk') but I need to somehow cast them as a string value. Am I right in thinking that, and if so how can this be achieved?
You can add to your template to allow user to input user_username and save that username to q3:
q3 = self.request.GET.get('user_username')
After that you can adjust your If condition accordingly, then change your return to something like:
Profile.objects.filter(Q(first_name__icontains=q1) |
Q(last_name__icontains=q1),
location__icontains=q2,
user__username=q3)
Hi i have a django model for notification which have a many-to-many relation but nothing appears in django admin ( all fields do not appear)
class Notification(models.Model):
"""send notification model"""
title = models.CharField(max_length=200)
text = models.TextField(null=True, blank=True)
device = models.ManyToManyField(Device, null=True, blank=True)
country = models.ManyToManyField(Country, null=True, blank=True)
sent = models.BooleanField(default=False)
when i open django admin for this model and press add notification this is what happens (nothing appears)
Country and Device Code
class Device(models.Model):
"""Store device related to :model:`accounts.User`."""
user = models.OneToOneField(User, related_name='device', on_delete=models.CASCADE)
model = models.CharField(max_length=200, blank=True, null=True)
player_id = models.CharField(max_length=200, blank=True, null=True)
class Meta:
verbose_name = 'Device'
verbose_name_plural = 'Devices'
def __str__(self):
return self.model
class Country(models.Model):
name = models.CharField(max_length=255)
def __str__(self):
return self.name
Admin.py
from django.contrib import admin
from .models import Notification
admin.site.register(Notification)
Edit:
Thank you all the problem is solved
The problem was caused by some entries in device model that did have None in the model field so there was a problem displaying it correctly.
According to https://code.djangoproject.com/ticket/2169 :
When a class has a field that isn't shown in the admin interface but
must not be blank, it's impossible to add a new one. You get a cryptic
"Please correct the error below." message with no shown errors. The
error message should probably say something about a hidden field.
Now ManyToManyFields don't need null=True, try removing those statements and see if you get an improvement.
Also, try adding the Country and Device models in admin.py so admin can see them and display them.
https://docs.djangoproject.com/en/1.11/ref/contrib/admin/#working-with-many-to-many-models
Define an inline for the many-to-manys in admin.py:
from django.contrib import admin
class DeviceInline(admin.TabularInline):
model = Notification.device.through
class CountryInline(admin.TabularInline):
model = Notification.country.through
class NotificationAdmin(admin.ModelAdmin):
inlines = [
DeviceInline, CountryInline
]
exclude = ("device", "country")
I have created a model as below.
class UserPost(models.Model):
author = models.ForeignKey(User, related_name='userpost', null=True, on_delete=models.CASCADE)
post_date = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=150, blank=False)
post_body = models.TextField(blank=True, null=True, default='text')
image = models.ImageField(upload_to='post_pics', blank=True)
likes = models.ManyToManyField(User, blank=True, related_name='post_likes')
I am not populating likes field anywhere, my admin screenshot is below.Why my likes field is getting populated with all the users created?
admin screenshot
admin.py
from django.contrib import admin
from feed.models import UserPost
# Register your models here.
admin.site.register(UserPost)
Edit 1:
Adding a screenshot for Rishabh's answer.
trying to add user from left as suggested by him
You are using ManyToManyField of Django which will show you all records of User table left side and you can add them by double clicking on them or by clicking '+' sign, so your likes field is not prepopulated at all it is just showing User table data.
I am trying to validate a form field in a ModelForm based on the value of another field in a different model.
Here is my ModelForm. CompanyData Model contains an "arr" field that I want to use as the value to validate against (that the "rev_goal" is higher):
from django.forms import ModelForm
from django import forms
from django.core.exceptions import ValidationError
from company_data.models import CompanyData
from plans.models import Plan
class PlanCreateForm(forms.ModelForm):
def clean_rev_goal(self):
rev_goal = self.cleaned_data['rev_goal']
company_data = self.object.companydata = CompanyData.objects.get # This is wrong. But how do I get the arr field from CompanyData here so the next line of code works?**
if rev_goal < company_data.arr:
raise ValidationError("Revenue goal must be greater than current ARR $")
return rev_goal
class Meta:
model = Plan
fields = ['plan_name', 'rev_goal', 'months_to_project', 'cpl', 'conv_rate']
More detail was requested so here are the two models showing the relationships between the two:
class CompanyData(models.Model):
user = models.OneToOneField(User)
arr = models.DecimalField(max_digits=20, decimal_places=2, validators=[MinValueValidator(1)])
num_cust = models.IntegerField(validators=[MinValueValidator(1)])
class Plan(models.Model):
companydata = models.ForeignKey(CompanyData, related_name='companydata',
on_delete=models.CASCADE)
user = models.ForeignKey(User)
plan_name = models.CharField(max_length=255)
rev_goal = models.DecimalField(max_digits=20, decimal_places=2, validators=[validate_rev_goal])
months_to_project = models.DecimalField(max_digits=20, decimal_places=0, validators=[MinValueValidator(1)])
cpl = models.DecimalField(max_digits=20, decimal_places=2, validators=[MinValueValidator(.01)])
conv_rate = models.DecimalField(max_digits=5, decimal_places=2, validators=[MinValueValidator(.01)])
And I going about this completely wrong? Or is it possible to access the value of a field of a different model in a ModelForm? Thanks in advance for your help!