just like the pic in admin panel when creating some post:
that basically one of dropdown menu options, it is so long, is there any idea on how i can change it to be multi-line? or maybe change the drop down menu to a "select table", the admin in this case need to read the description, so it is unwise for it to be formatted like that.
I have a code example:
models.py
class CreatePost(models.Model):
subject = models.CharField(max_length=99)
desc = models.TextField(max_length=9000)
isSolved = models.BooleanField(default=False) # a button
user = models.ForeignKey(User, on_delete=models.CASCADE,related_name="user_post")
def __str__(self):
return format_html('SUBJECT : {} <br/> DESCRIPTION : {} <br/> Email : {} <br/> ',self.subject, self.desc, self.user.username)
# remember to show the name of ticket sender
class RespondToPost(models.Model):
ticket = models.ForeignKey(CreatePost,on_delete=models.CASCADE)
to = models.EmailField(max_length=320)
content = models.TextField()
def __str__(self):
return format_html('SUBJECT : {} <br/> DESCRIPTION : {} <br/> EMAIL : {} <br/> ',self.post.subject, self.post.desc, self.post.user.username)
admin.py
class CreatePostAdmin(admin.ModelAdmin):
list_display = ('id', '__str__')
class Meta:
model = models.CreatePost
class RespondToPostAdmin(admin.ModelAdmin):
list_display = ('id', '__str__', 'to', 'content')
class Meta:
model = models.RespondToPost
any idea?
You can add a custom field to list_display and change its content however you like:
from django.utils.text import Truncator # for shortening a text
class CreatePostAdmin(admin.ModelAdmin):
list_display = ('id', 'get_truncated_str')
class Meta:
model = models.CreatePost
def get_truncated_str(self, obj):
# Change it however you want, shortening is just an example
return Truncator(str(obj)).words(10)
Related
I have these models
class SubjectTeacher(models.Model):
teacher = models.ForeignKey(TeacherProfile, on_delete=models.CASCADE)
subject = models.ForeignKey(Subject, on_delete=models.CASCADE)
SEMESTER_CHOICES = [("1st", "First Quarter"), ("2nd", 'Second Quarter'), ('3rd', 'Third Quarter'), ('4th', 'Fourth Quarter')]
semester = models.CharField(choices = SEMESTER_CHOICES, default = "1st", max_length=3)
students = models.ManyToManyField(StudentProfile, related_name="subjects")
def __str__(self):
return f'{self.subject.subject_name} | {self.teacher.user.first_name}'
class Meta:
constraints = [
UniqueConstraint(fields = ["teacher", "subject"], name = "Unique Subject Teacher")
]
class StudentGrade(models.Model):
subject_teacher = models.ForeignKey("SubjectTeacher", on_delete=models.CASCADE)
student = models.ForeignKey('StudentProfile', on_delete=models.CASCADE)
grade = models.IntegerField()
now I want StudentGrade.student to be based on what is selected (in django-admin) on the StudentGrade.subject_teacher
Example:
subject_teacher = <subject1> <subject2>
selected: <subject1>
student = choices from <subject1>.students
I already tried looking on similar cases such as editing the ModelForm but I couldn't get the gist of it.
If you want to use a model form that has a filtered queryset, you can do so like this:
# forms.py
class MyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.students = StudentProfile.objects.filter( # your filter )
super(MyForm, self).__init__(*args, **kwargs)
self.fields['students'].queryset = self.students
If you are adding a StudentGrade directly in the Django Admin then it won't know which subject_teacher you want and will show a <select> with all the options. You would need to specify the subject_teacher before the form is initiated for the filter to work the way you want.
I try to do tabular inline admin.
In the child tab, if we include a ForeignKey field, it will show the str property of that foreign model.
But how to also show another property of that foreign model?
Here is my models.py
class RawMaterial(models.Model):
name = models.CharField(max_length=15)
ubuy = models.CharField(max_length=5)
usell = models.CharField(max_length=5)
uconv = models.DecimalField(max_digits = 5,decimal_places=2)
def __str__(self):
return self.name
class Coctail(models.Model):
name = models.CharField(max_length=20)
def __str__(self):
return self.name
class Ingredient(models.Model):
coctail = models.ForeignKey(Coctail,
related_name='ingredient',
on_delete=models.CASCADE)
rawmaterial = models.ForeignKey(RawMaterial,
related_name='ingredient',
on_delete=models.CASCADE)
qty = models.DecimalField(max_digits = 5,decimal_places=2)
def __str__(self):
return self.rawmaterial
def rawusell(self):
return self.rawmaterial.usell
rawusell.short_description = 'UOM'
Here is my admin.py
from django.contrib import admin
# Register your models here.
from .models import *
admin.site.register(RawMaterial)
class IngredientInline(admin.TabularInline):
model = Ingredient
list_display = ('rawmaterial', 'qty', 'rawusell')
class CoctailAdmin(admin.ModelAdmin):
inlines = [IngredientInline]
admin.site.register(Coctail, CoctailAdmin)
and here what I got
My question is : How to show rawmaterial.usell in Ingredient tab?
Sincerely
-bino-
You can show the rawmaterial.usell field in the ingredient tab but it will not be editable. Since, any field can only be editable if they are a field of that model (Without using any custom form and logic).
So, if you want rawmaterial.usell to be editable, you will have to make a rawmaterial admin
You can show the rawmaterial.usell in IngredientInline by doing this.
class IngredientInline(admin.TabularInline):
model = Ingredient
readonly_fields = ('rawusell', )
list_display = ('rawmaterial', 'qty', 'rawusell')
def rawusell(self, obj):
return obj.rawmaterial.usell
This will start showing usell in the inline admin.
Let's say I have models:
from filer.fields.image import FilerImageField()
class Image(models.Model):
name = models.CharField(max_length=128)
image = FilerImageField()
class City(models.Model):
name = models.CharField(max_length=128)
images = models.ManyToManyField(Image, blank=True)
admin.py:
class ImageAdmin(admin.ModelAdmin):
def thumb(self, obj):
return '<img src=%s />' %obj.image.icons['64']
thumb.short_description = 'Preview'
thumb.allow_tags = True
list_display = ('image', 'name', 'thumb', )
class CityAdmin(models.ModelAdmin):
filter_horizontal = ('images', )
admin.site.register(Image, ImageAdmin)
admin.site.register(City, CityAdmin)
Questions:
1. How to add "+" button in CityAdmin above m2m widget? Currently what i have:
2. Is it possible in CityAdmin m2m widget have some list display where I can see image thumbnail? Ideally like in ImageAdmin:
What I have tried:
In Image model __unicode__ function return '<img src=%s />' %self.image.icons['64'], but then in admin it just displays raw text.
I have created two models Article and Author as this:
model.py
class Article(models.Model):
title = models.CharField(max_length=200)
content = models.TextField(max_length = 5000)
author = models.ForeignKey('Author', on_delete=models.CASCADE)
class Author(models.Model):
author_name = models.CharField(max_length=200)
author_intro = models.TextField(max_length = 3000)
And I am trying to create a form that lets user input Article information *(including title, content, author only). So that whenever user input an author, that input data is stored in both author (in Article model) and author_name (in Author model). Is this possible to do? I can not seem to get it working. Here's what I tried:
form.py:
class articleForm(forms.ModelForm):
author = forms.ModelMultipleChoiceField(queryset=Author.objects.all())
class Meta:
model = Article
fields = ['title']
widgets = {
'content': forms.Textarea(attrs={'cols': 75, 'rows': 50})}
class authorForm(forms.ModelForm):
class Meta:
model = Author
fields = ['author_name']
views.py:
def compose_article(request):
form_article = articleForm(request.POST or None)
if form_article.is_valid():
instance = form_article.save(commit=False)
instance.save()
context = {
"ArtileForm":form_article,
}
return render(request,"Upload.html",context)
Thanks in advance!
You need to provide the author name input as a char field and handle getting or creating the author manually.
You also need to set unique=True on author_name. Try a form like this:
class ArticleForm(forms.ModelForm):
author = forms.CharField()
class Meta:
model = Article
fields = ['title', 'author', 'content']
widgets = {
'content': forms.Textarea(attrs={'cols': 75, 'rows': 50}),
}
def save(self, commit=True):
author, created = Author.objects.get_or_create(
author_name=self.cleaned_data['author'],
defaults={'author_intro': ''}
)
self.cleaned_data['author'] = author.id
return super(ArticleForm, self).save(commit)
And a view like this:
from django.views.generic.edit import CreateView
class ArticleFormView(CreateView):
form_class = ArticleForm
template_name = 'Upload.html'
# You can skip this method if you change "ArtileForm" to "form"
# in your template.
def get_context_data(self, **kwargs):
cd = super(ArticleFormView, self).get_context_data(**kwargs)
cd['ArtileForm'] = cd['form']
return cd
compose_article = ArticleFormView.as_view()
what worked for me was to move the code from the save to clean
def clean(self):
group, created = Ideas_Group.objects.get_or_create(
category_text=self.cleaned_data.get('group'))
self.cleaned_data['group'] = group
return super(IdeasForm, self).clean()
and then in the views.py was just a regular process
def post(self, request):
if request.method == 'POST':
form = IdeasForm(request.POST)
if form.is_valid():
ideapost = form.save(commit=False)
ideapost.save()
I've just arrived here about a similar problem. Starting with your code, in my case, I've added "__id".
class articleForm(forms.ModelForm):
author__id = forms.IntegerField(...
Printing this part of the form. (27 is the id of my testcase.)
<tr><th><label for="id_author">Author:</label></th><td><select name="author" required id="id_author">
<option value="">---------</option>
<option value="27" selected>Author</option>
</select></td></tr>
Essence in the following.
I have a few different Magazine. And AutoForm from template shows all Articles and all Authors for possible selection (not only from current Magazine). How to restrict this choice of author a for article only from the current magazine? Can I do this using only the Template? If not, then how?
models.py
class Magazine(models.Model):
Name = models.CharField(max_length=200)
class Article(models.Model):
Name = models.CharField(max_length=200)
Magazine = models.ForeignKey(Magazine)
class Author(models.Model):
Name = models.CharField(max_length=200)
Magazine = models.ForeignKey(Magazine)
class Sets(models.Model):
Name = models.CharField(max_length=200)
Magazine = models.ForeignKey(Magazine)
Aut = models.ManyToManyField(Author, null=True, blank=True)
Set = models.ForeignKey(Article, null=True, blank=True)
forms.py:
class MagazineForm(ModelForm):
class Meta:
model = Magazine
fields = {'Name'}
class ArticleForm(ModelForm):
class Meta:
model = Article
fields = {'Name'}
class AuthorForm(ModelForm):
class Meta:
model = Author
fields = {'Name'}
class SetsForm(ModelForm):
class Meta:
model = Sets
fields = {'Name', 'Set', 'Aut'}
views.py
def building_details(request, magazine_id):
sets_form = SetsForm
args = {}
args.update(csrf(request))
args['magazine'] = Magazine.objects.get(id=magazine_id)
args['article'] = Article.objects.filter(Magazine=magazine_id)
args['author'] = Author.objects.filter(Magazine=magazine_id)
args['sets'] = Sets.objects.filter(Magazine=magazine_id)
args['setform'] = sets_form
return render_to_response('building.html', args)
Template
<form action='/add/{{ magazine.id }}/' method='post'>
{% csrf_token %}
{{ setform }}
<input type='submit' class='button' value="Добавить">
</form>
</div>
Maybe somewhere in this entry there are errors (I briefly edited, removing not playing a role here, essentially). In General I have everything working right, except that all objects are displayed, instead of only having the current.
Sounds like you are trying to restrict the options in the ForeignKey selector based on some criteria.
This means you need to override some of the details in the forms __init__ method:
class SetsForm(ModelForm):
class Meta:
model = Sets
fields = {'Name', 'Set', 'Aut'}
def __init__(self, *args, **kwargs):
articles = Article.objects.filter(Magazine=kwargs.pop('magazine_id'))
super(SetsForm, self).__init__(*args, **kwargs)
self.fields['articles'] = forms.ModelChoiceField(
queryset=articles ,
label="Articles",
)
Then call your form like so:
sets_form = SetsForm(magazine_id=magazine_id)
To get authors of articles only in the current magazine:
articles = Article.objects.filter(Magazine=magazine_id)
sets = Sets.objects.filter(Magazine=magazine_id, Set__in=articles)
import itertools
# build a flat list of all Authors in these sets (and call `set` to avoid duplicates)
authors = set(itertools.chain(*[s.Aut.all() for s in sets]))
This would be easier if there were a direct foreign key on Author to Article.
Also, you should follow Django convention by using lowercase field names. This will avoid confusion between fields and models, which use uppercase.