New attributes are not showing up in django admin dashboard - django

Previously I was using my project with sqlite. Then started a new project copied the data from previous project and made some changes, and I'm using this with mysql.
This is my models.py(not full)
from django.db import models
from django.db.models import CheckConstraint, Q, F
class College(models.Model):
CITY_CHOICES=[('BAN','Bangalore')]
id=models.IntegerField(primary_key=True)
name=models.CharField(max_length=50)
city=models.CharField(choices=CITY_CHOICES,default='BAN',max_length=10)
fest_nos=models.IntegerField()
image=models.ImageField(default='default.jpg',upload_to='college_pics')
class Meta():
db_table='college'
def __str__(self):
return self.name
class Organizer(models.Model):
id=models.IntegerField(primary_key=True)
name=models.CharField(max_length=25)
phone=models.IntegerField()
def __str__(self):
return self.name
class Fest(models.Model):
FEST_CHOICES=[
('CUL','Cultural'),
('TEC','Technical'),
('COL','College'),
('SPO','Sports'),
]
id=models.IntegerField(primary_key=True)
name=models.CharField(max_length=50)
clg_id=models.ForeignKey(College,on_delete=models.CASCADE)
fest_type=models.CharField(choices=FEST_CHOICES,default='COL',max_length=10)
fest_desc=models.TextField(default='This is a fest')
#below two field are not showing up in admin page
start_date=models.DateField(auto_now_add=True)
end_date=models.DateField(auto_now_add=True)
event_nos=models.IntegerField()
org_id=models.ManyToManyField(Organizer)
image=models.ImageField(default='default.jpg',upload_to='fest_pics')
class Meta:
constraints = [
CheckConstraint(
check = Q(end_date__gte=F('start_date')),
name = 'check_start_date',
)
]
db_table='fest'
def __str__(self):
return self.name
The start_date and end_date attributes are the new ones added in this project. It was not there in the old one.
My admin.py file
from django.contrib import admin
from .models import College, Event, Fest, Organizer, Participated
admin.site.register(College)
admin.site.register(Organizer)
admin.site.register(Fest)
admin.site.register(Event)
admin.site.register(Participated)
But in my admin dashboard, while adding new fests I'm not getting the option to add start and end date.
I made migrations once again, fake migrated etc. What to do?
Is check constraint under model fest causing this problem?

They fields won't show up on Django Admin because they have auto_now_add=True so, the user shouldn't touch them.

You can make auto_now_add field display in admin by using readonly_fields in the admin class(this only show the data, you still can't edit it because it's auto_now_add)
#register with a class to use
class FestAdmin(admin.ModelAdmin):
readonly_fields = ('start_date', 'end_date')
admin.site.register(Fest, FestAdmin)

Related

Django - automate CRUD from models (DRY approach)?

I am new to Django but not to developing.
I need to make an application in which user can do CRUD operations (Create, Read, Update, Delete). This functionality should apply to all models and the fields for Create & Update will be auto-generated from model attributes.
What I describe is pretty much the functionality that comes with the Admin page. However, I want to use it in my own app instead of using the Admin app.
For example, let's suppose we have Author and Book models:
(models.py)
from django.db import models
class Author(models.Model):
first_name = models.CharField(max_length=60)
last_name = models.CharField(max_length=60)
def __str__(self):
return self.last_name
class Book(models.Model):
title = models.CharField(max_length=60)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
def __str__(self):
return self.title
I suppose that the above information (models) could be enough for CRUD operations, without repeating code of the same logic for each model. I am aiming at a functionality like in admin page where all you have to do is register your model.
I am aware of ModelForm and Generic Views but while they help avoiding hard-coding form fields, I have not found a non-repetitive coding approach. I would like to avoid approaches like the following where same code is being duplicated for each model:
(forms.py)
from django import forms
from todo.models import Author, Book
class AuthorForm(forms.ModelForm):
class Meta:
model = Author
fields = '__all__'
class BookForm(forms.ModelForm):
class Meta:
model = Book
fields = '__all__'
(views.py)
from django.views.generic import CreateView
from.forms import AuthorForm, BookForm
from.models import Author, Book
class AuthorCreateView(CreateView):
model = Author
form_class = AuthorForm
...
class BookCreateView(CreateView):
model = Book
form_class = BookForm
...
So, what is the best approach for a DRY CRUD solution (like in Admin page)? Am I missing any Django features?
Putting my explanation in the comment together, you would get something like this:
from django.views import generic
from myapp.apps import MyAppConfig
from django.forms import modelform_factory
urlpatterns = []
for model in MyAppConfig.get_models():
create_url = path(
f"{model.__class___.__name__.lower()}/create",
generic.CreateView.as_view(
form_class=modelform_factory(model=model, fields='__all__'),
template_name=f"{model._meta.app_label}/create.html",
model=model
),
),
list_url = path(
f"{model.__class__.__name__.lower()}/",
generic.ListView.as_view(
template_name=f"{model._meta.app_label}/list.html",
model=model
),
),
...
urlpatterns.extend([create_url, list_url, read_url, update_url, delete_url])
So the principle is to use the generic view and model form factory, to generate standard crud views, derive path names from model name and use one template per view, in the application (derived from model's app_label).
Using the documentation I linked before, you should be able to piece things together.

Registering derived child class of abstract class in admin.py in django 2.2

Does anyone know, how to register child class derived from abstract class in admin.py (the abstract class is in file abstract_models.py file) I tried major solution in the web but does not seem to work. It is possible as pointed by various contributors but don't know what I am doing wrong!
My folder structure is like this
'''
gaasc/ <- project folder
contain urls.py, admin.py,models.py,etc
gaasc_apps/<- contains all apps
core/
abstract_models.py
models.py
admin.py,...
about_app/
models.py,
admin.py
urls.py
'''
I am trying to leverage abstract class inside core app to models inside about_app app. Yes, between different apps.
Steps followed:
create abstract_models.py and define abstract class
import it in core/models.py
3.import the abstract class from core/models.py inside about_app/models.py
register the class in about_app/models.py to admin.py(in about_app/)
abstract_models.py file(inside core/abstract_models.py) has
import uuid
from django.db import models
class AbstractTimeStampModel(models.Model):
"""TimeStampModel that holds created_date and updated_date field"""
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
created_date = models.DateTimeField("Created date", auto_now_add=True)
updated_date = models.DateTimeField("Updated date", auto_now=True)
def __str__(self):
return self.created_date
class Meta:
abstract = True
class AbstractTextAreaOnly(AbstractTimeStampModel):
"""Abstract class for textfield"""
about = models.TextField(
verbose_name="Description",
blank=True
)
def __str__(self):
return "Textonly class-"+self.id
class Meta:
ordering = ['created_date']
models.py in core/models.py
from django.db import models
from .abstract_models import (
AbstractTextAreaOnly,
)
Now I want to use this abstract class in about_app/
So my derived class in models.py inside about_app/models.py looks:
from django.db import models
from gaasc_apps.core.models import(
AbstractTextAreaOnly,
)
class GeneralInformation(AbstractTextAreaOnly):
'''
Gives general information of college
'''
class Meta():
db_table = "general_information"
verbose_name="General information"
ordering=['created_date']
What I tried:
I tried to registering using following ways:
method1:
in admin.py in about_app/admin.py:
from django.contrib import admin
from .models import (
GeneralInformation,
)
#register(GeneralInformation)
class GeneralInformationAdmin(admin.ModelAdmin):
pass
method 2:
in about_app/admin.py
from django.contrib import admin
from .models import (
GeneralInformation,
)
class GeneralInformationAdmin(admin.ModelAdmin):
pass
admin.site.register(GeneralInformation,GeneralInformationAdmin)
method3:
in about_app/admin.py
......
class GeneralInformationAdmin(admin.ModelAdmin):
readonly_fields = ('id','about','created_date','updated_date')
list_display=('id','about','created_date')
fieldsets=[
('Id',{'fields':['id']}),
('About',{'fields':['about']}),
('Created_Date',{'fields':['created_date']}),
]
admin.site.register(GeneralInformation,GeneralInformationAdmin)
With all this solution GeneralInformation is not shown in admin panal/dashboard of django.
The solution seems to be simple but I don't know why its not working?
Some solution I tried are here:
How to register inherited sub class in admin.py file in django?
Django admin model Inheritance is it possible?
Register abstract model in admin django 1.6
VERSION:
Django-2.2
python-3.6
I have found the solution to the problem , it was simple
we need to define config setting in each apps. Due to lack of config setting and perticular directory structure it was not able to read it.E.g.
in about_app/__init__.py :
default_app_config = "gaasc_apps.about_app.apps.AboutAppConfig"
and in about_app/apps.py we should have like this
from django.apps import AppConfig
class AboutAppConfig(AppConfig):
name = 'gaasc_apps.about_app'
verbose_name="about application"
def ready(self):
pass

How to query by joining a Django Model with other, on a non unique column?

I have the following models in my models.py file in my django project
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.conf import settings
class CustomUser(AbstractUser):
pass
# add additional fields in here
class PDFForm(models.Model):
pdf_type=models.IntegerField(default=0)
pdf_name=models.CharField(max_length=100,default='')
file_path=models.FileField(default='')
class FormField(models.Model):
fk_pdf_id=models.ForeignKey('PDFForm', on_delete=models.CASCADE,default=0)
field_type=models.IntegerField(default=0)
field_page_number=models.IntegerField(default=0)
field_x=models.DecimalField(max_digits=6,decimal_places=2,default=0)
field_y=models.DecimalField(max_digits=6,decimal_places=2,default=0)
field_x_increment=models.DecimalField(max_digits=6,decimal_places=2,default=0)
class Meta:
ordering= ("field_page_number", "field_type")
class UserData(models.Model):
fk_user_id=models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE,default=0)
field_type=models.IntegerField(default=0)
field_text=models.CharField(max_length=200,default='')
field_date=models.DateField()
Here is how the models are related
1) a pdfform contains a pdf form and path for it on the file system
2) A pdfform has multiple FormFields in it. Each field has attributes, and the specific one under discussion is field_type
3)The UserData model has user's data, so one User can have multiple rows in this table. This model also has the field_type column.
What I am trying to query is to find out all rows present in the Userdata Model which are present in the FormField Model ( matched with field_type) and that are of a specific PDFForm.
Given that the Many to Many relationship in django models cannot happen between no unique fields, how would one go about making a query like below
select a.*, b.* from FormField a, UserData b where b.fk_user_id=1 and a.fk_pdf_id=3 and a.field_type=b.field_type
I have been going through the documentation with a fine toothed comb, but obviously have been missing how django creates joins. what is the way to make the above sql statement happen, so I get the required dataset?
I think UserData is missing a relation to FormField, but if you had this relation you could do:
UserData.objects.filter(
fk_user_id=1, # Rename this to user, Django wilt automicly create a user_id column
form_field__in=FormField.objects.filter(
fk_pdf_id=<your pdfid> # same as fk_user_id
)
)
Edit updated models
When you use a ForeignKey you don't have to specify the _id or default=0, if you don't always want to fill the field its better to set null=True and blank=True
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.conf import settings
class CustomUser(AbstractUser):
pass
# add additional fields in here
class FieldTypeMixin:
TYPE_TEXT = 10
TYPE_DATE = 20
TYPE_CHOISES = [
(TYPE_TEXT, 'Text'),
(TYPE_DATE, 'Date'),
]
field_type=models.IntegerField(default=TYPE_TEXT, choises=TYPE_CHOISES)
class PDFForm(models.Model):
pdf_type = models.IntegerField(default=0)
pdf_name = models.CharField(max_length=100,default='')
file_path = models.FileField(default='')
class FormField(models.Model, FieldTypeMixin):
pdf_form = models.ForeignKey('PDFForm', on_delete=models.CASCADE)
field_page_number = models.IntegerField(default=0)
field_x = models.DecimalField(max_digits=6,decimal_places=2,default=0)
field_y = models.DecimalField(max_digits=6,decimal_places=2,default=0)
field_x_increment = models.DecimalField(max_digits=6,decimal_places=2,default=0)
class Meta:
ordering = ("field_page_number", "field_type")
class SubmittedForm(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, models.CASCADE)
pdf_form = models.ForeignKey(PDFForm, models.CASCADE)
class SubmittedFormField(models.Model, FieldTypeMixin):
submitted_form = models.ForeignKey(SubmittedForm, models.CASCADE)
form_field = models.ForeignKey(FormField, models.CASCADE, related_name='fields')
field_text = models.CharField(max_length=200,default='')
field_date = models.DateField()
class Meta:
unique_together = [
['submitted_form', 'form_field']
]

admin.py: "model = Thing" ,what does this code mean?if without it what gonna happen?

every one,,I am reading a Django practice book,,I saw a code "model = Thing" in admin.py,,,however, when I remove "model = Thing",,,the web program still can run,the admin site looks no difference??,what does this code mean?if without it what gonna happen? my models.py class is Thing
admin.py
from django.contrib import admin
from collection.models import Thing
class ThingAdmin(admin.ModelAdmin):
model = Thing #if I remove this code, the program still can run,,why need this code
list_display = ('name', 'description',)
prepopulated_fields = {'slug': ('name',)}
admin.site.register(Thing, ThingAdmin)
modles.py
from django.db import models
class Thing(models.Model):
name = models.CharField(max_length=255)
description = models.TextField()
slug = models.SlugField(unique=True)
Setting a model attribute on the ModelAdmin class will have no effect. You can safely remove that line from your code.
In the Django admin, you specify the model when you call admin.site.register(), or by using the register decorator. This allows you to use the same model admin class for more than one model.
admin.site.register(Thing, ThingAdmin)
admin.site.register(OtherThing, ThingAdmin)
As Jon pointed out in the comments, you do need to specify the model for InlineModelAdmin objects.

Why do I have to reference the user model this way

I was working on a Django project and I was trying to do something like this to make sure that my model worked no matter what user model is set.
from django.contrib.auth import get_user_model
class Item(models.Model):
title = models.CharField(max_length=100, )
description = models.TextField()
seller = models.ForeignKey(get_user_model())
However when I did this it resulted in errors telling me the user model couldn't be accessed so I had to change it to this
from django.conf import settings
class Item(models.Model):
title = models.CharField(max_length=100, )
description = models.TextField()
seller = models.ForeignKey(settings.AUTH_USER_MODEL)
This works fine but I thought I have done this in the past using the first method. The only difference that time being that I was using a custom user model. They both seem like they are doing the same thing to me so why do I have to use the second method? And does get_user_model() not work with the default user?
This is the source code of the get_user_model() in django:
def get_user_model():
"""
Returns the User model that is active in this project.
"""
from django.db.models import get_model
try:
app_label, model_name = settings.AUTH_USER_MODEL.split('.')
except ValueError:
raise ImproperlyConfigured("AUTH_USER_MODEL must be of the form 'app_label.model_name'")
user_model = get_model(app_label, model_name)
if user_model is None:
raise ImproperlyConfigured("AUTH_USER_MODEL refers to model '%s' that has not been installed" % settings.AUTH_USER_MODEL)
return user_model
As you can see, it pulls the AUTH_USER_MODEL variable from your settings as you do but extracting the app_label and the user class itself. If it does not work you should see one of the two errors in the terminal when this call is done.
I think your answer lies in the Django source. It depends on your setup what happens. Older versions might do it a bit differently.