Why TabularInline looks different on differen sites. How to control its apperence - python

I have 2 different registers on my admin panel and on one TabularInline allows multiple choice:
and on another not:
Where does the difference come from? How can I control it?
Update:
I have a table movies which is connected to the table person via intermediate table. Table Person has name and role (actor, writer, director). What I am trying to do is to allow in admin panel to see and edit both, e.g. Movies should have 3 different panels, where one can add actor, writer and director. Actor should have name and movie to add.
So far I was able to make 3 panels for movies, but they do not allow several choices and show all names, but not only actors in actors panel (see second picture). Also when I save them, they do not get role - actor. Actors allow to choose several movies, but when I save them, admin blocks me saying "Film work person with this Movie already exists."
My models (I only show part for films and actors, writers and director are the same):
class FilmWorkPerson(models.Model):
id = models.AutoField(primary_key=True, editable=False)
movie = models.OneToOneField('FilmWork', models.CASCADE, unique=False)
person = models.ForeignKey('Person', models.CASCADE, unique=False)
created_on = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'film_work_person'
unique_together = (('movie', 'person'),)
class FilmWork(models.Model):
# what we have from sql
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
title = models.CharField(max_length=255)
people = models.ManyToManyField('Person', through=FilmWorkPerson)
class Person(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
name = models.CharField(_('ФИО'), max_length=100)
role = models.CharField(_('роль'), max_length=100)
created_on = models.DateTimeField(auto_now =True)
movie = models.ManyToManyField(FilmWork, through=FilmWorkPerson)
class Meta:
db_table = 'person'
def __str__(self):
return self.name
class ActorManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(role='actor')
class Actor(Person):
objects = ActorManager()
class Meta:
proxy = True
verbose_name = _('actor')
verbose_name_plural = _('actors')
my admin.py:
class PersonInlineAdmin(admin.TabularInline):
model = Person.movie.through
class ActorInlineFormSet(BaseInlineFormSet):
def get_queryset(self):
qs = super(ActorInlineFormSet, self).get_queryset().filter(person__role__iexact='actor')
self._queryset = qs
return self._queryset
class ActorInlineAdmin2(admin.TabularInline):
model = FilmWork.people.through
formset = ActorInlineFormSet
verbose_name = 'actor'
verbose_name_plural = 'actors'
#admin.register(FilmWork)
class FilmworkAdmin(admin.ModelAdmin):
# отображение полей в списке
list_display = ('title', 'ratings', 'created_on', 'actors', 'writers', 'director',
'film_creation_date', 'age_limit', 'link')
def actors(self, obj):
actors = FilmWork.objects.filter(person__role__iexact='actor', title=obj).values_list('person__name', flat=True)
return ", ".join([a for a in actors])
def writers(self, obj):
writers = FilmWork.objects.filter(people__role__iexact='writer', title=obj).values_list('people__name', flat=True)
return ", ".join([a for a in writers])
def director(self, obj):
director = FilmWork.objects.filter(people__role__iexact='director', title=obj).values_list('people__name', flat=True)
return ", ".join([a for a in director])
list_filter = ('genre','film_creation_date', 'age_limit', 'link')
fields = ('title', 'plot', 'ratings', 'film_creation_date', 'age_limit', 'link')
search_fields = ('title', 'plot', 'id', 'film_creation_date', 'age_limit', 'link')
inlines = (GenreInlineAdmin, ActorInlineAdmin2, DirectorInlineAdmin2, WriterInlineAdmin2, )
#admin.register(Actor)
class Actor(admin.ModelAdmin):
list_display = ('name', )
fields = ('name', )
search_fields = ('name', 'movie')
list_filter = ('movie',)
inlines = (PersonInlineAdmin,)

I'm not sure if I understand your question clearly, but I'm guessing it's because of the different relationship types between the models, models.ForeignKey for the Genre vs models.ManyToManyField for the Movie.
If you can provide more details on what you're trying to achieve, I might be able to help.

Related

How to filter/hide fields in django rest framework HTML form using authenticated user

I created two models:
parcel (package) model,
'shelf' model to which parcels can be assigned.
class Parcel(models.Model):
owner = models.ForeignKey(get_user_model(), on_delete=models.PROTECT)
name = models.CharField(max_length=100, blank=False)
contents = models.TextField(blank=False, validators=[MaxLengthValidator(1500)])
size = models.CharField(max_length=50, blank=True, validators=[package_size_validator])
weight = models.PositiveIntegerField(blank=True, null=True)
contact = models.CharField(max_length=50, blank=True)
creation_date = models.DateTimeField(auto_now_add=True)
last_modification = models.DateTimeField(auto_now=True)
code = models.CharField(max_length=30, unique=True, blank=False)
def __str__(self):
return f'Parcel: {self.code}, {self.owner}, {self.name}'
class ParcelShelf(models.Model):
owner = models.ForeignKey(get_user_model(), on_delete=models.PROTECT)
name = models.CharField(max_length=100, blank=False)
creation_date = models.DateTimeField(auto_now_add=True)
last_modification = models.DateTimeField(auto_now=True)
parcels = models.ManyToManyField('Parcel', blank=True, related_name='shelf_parcel')
def __str__(self):
return f'ParcelShelf: {self.owner}, {self.name}'
I came to a solution where the logged-in user can see only his packages and shelves. The problem I have is with the many-to-many relationship where parcels can be added to shelves. I want to come to a solution where the logged in user can add to the shelf only those parcels which he is the owner, creator. It will look better in pictures.
All packages created by user t2#t2.com (user id = 17):
parcels list
Now the view when the user t2#t2.com wants to create a shelf:
shelf list
All packages are visible, while only those created by the user t2#t2.com should be available.
Code to serializer:
class ParcelShelfSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.email')
parcels = serializers.HyperlinkedRelatedField(many=True, read_only=False, view_name='parcels_detail_view',
# queryset=Parcel.objects.filter(owner=17)
queryset=Parcel.objects.all()
)
class Meta:
model = ParcelShelf
fields = ('id', 'owner', 'name', 'creation_date', 'last_modification', 'parcels')
Below is a picture where only packages for a given, logged-in user are available:
shelf list
Code to serializer:
class ParcelShelfSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.email')
parcels = serializers.HyperlinkedRelatedField(many=True, read_only=False, view_name='parcels_detail_view',
queryset=Parcel.objects.filter(owner=17)
# queryset=Parcel.objects.all()
)
class Meta:
model = ParcelShelf
fields = ('id', 'owner', 'name', 'creation_date', 'last_modification', 'parcels')
I got to the point where the 'solution' is in the 'queryset' argument.
All users: queryset=Parcel.objects.all()
Logged in user: queryset=Parcel.objects.filter(owner=17)
The problem is, this is hardcoded, and it should be something like: (owner=request.user). Unfortunately, I don't know how to achieve this in the serializer. I looked through other similar topics, but I didn't find a solution how to use the request method in the serializer field.
In addition, code in views:
class ParcelsShelfList(generics.ListCreateAPIView):
# queryset = ParcelShelf.objects.all()
serializer_class = ParcelShelfSerializer
def get_queryset(self):
user = self.request.user
if bool(user and user.is_staff and user.is_admin):
return ParcelShelf.objects.all()
else:
return ParcelShelf.objects.filter(owner=user)
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
UPDATE
Thanks to the help of #Amrez, who gave me a link to a similar topic, i was able to do it.
mentioned link: How can I filter DRF serializer HyperlinkedRelationField queryset based on request data?
I add this to my code in serializers.py:
def hyperlinked_related_field_by_owner(model, view_name, owner):
return serializers.HyperlinkedRelatedField(
many=True,
view_name=view_name,
queryset=model.objects.filter(owner=owner)
)
class ParcelShelfSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.email')
parcels = serializers.HyperlinkedRelatedField(many=True,
read_only=False,
view_name='parcels_detail_view',
# queryset=Parcel.objects.filter(owner=17)
queryset=Parcel.objects.all()
)
def get_fields(self):
fields = super().get_fields()
owner = self.context['request'].user
fields['parcels'] = hyperlinked_related_field_by_owner(Parcel, 'parcels_detail_view', owner)
return fields
class Meta:
model = ParcelShelf
fields = ('id', 'owner', 'name', 'creation_date', 'last_modification', 'parcels')

Django saving new record to a table with multiple foreign keys

So i basically have a model called Designations that derives foreign keys from 3 other models (curricula, role and staff) and i am trying to save a new record into the Designations model, the code below shows the Designations and Staffs model. However, for the Curriculum and role models i will not be showing as you can assume PK 1 in Curriula and role models will be used as data in the curriculum and role fields in Designation model
class Designations(models.Model):
designation_id = models.AutoField(primary_key=True)
curriculum = models.ForeignKey(Curricula, on_delete=models.CASCADE)
role = models.ForeignKey(Roles, on_delete=models.CASCADE)
staff = models.ForeignKey(Staffs, on_delete=models.CASCADE)
class Meta:
db_table = "arc_designations"
unique_together = ('curriculum', 'role', 'staff')
verbose_name_plural = "Designations"
ordering = ['designation_id']
def __str__(self):
return '%s of %s %s (%s)' % (self.role.role_name,
self.curriculum.course_period.course.course_abbreviation,
self.curriculum.module_period.module.module_abbreviation,
self.staff.staff_full_name)
class Staffs(models.Model):
staff_id = models.AutoField(primary_key=True)
admission_number = models.CharField(max_length=5,
unique=True,
help_text="Enter 5 digits",
validators=[numeric_only, MinLengthValidator(5)])
staff_full_name = models.CharField(max_length=70,
help_text="Enter staff's full name",
validators=[letters_only])
created_by = UserForeignKey(auto_user_add=True,
editable=False,
related_name="staff_created_by",
db_column="created_by")
created_at = models.DateTimeField(auto_now_add=True,
editable=False)
updated_by = UserForeignKey(auto_user=True,
editable=False,
related_name="staff_updated_by",
db_column="updated_by")
updated_at = models.DateTimeField(auto_now=True,
editable=False)
roles = models.ManyToManyField(Roles, through='Designations')
class Meta:
db_table = "arc_staffs"
verbose_name_plural = "Staffs"
ordering = ['staff_id']
def __str__(self):
return '%s (S%s)' % (self.staff_full_name, self.admission_number)
I have made a forms.py to get the admission_number(field in Staffs model)
class AssignRolesForm(forms.Form):
admission_no = forms.CharField(max_length=40,
widget=forms.TextInput(
attrs={'class': 'form-control', 'aria-describedby': 'add-btn'}))
Assuming that when i submit the form i would like for the admission_number entered in the form to reference into the Staffs model then get its PK to be saved into the staff field in Designations then as i said above, for the curriculum and role fields to referece PK 1 of their respective models. How would i write my function in views.py
**edit
I've tried writing out the view as suggested, heres the code below, currently i cant test my project so let me now if its correct
#require_POST
def setStaff(request):
form = AssignRolesForm(request.POST)
if form.is_valid():
Designations.staff = Staffs.objects.filter(admission_number=form.cleaned_data['admission_no'])
Designations.role = Roles.objects.get(pk=1)
Designations.curriculum = Curricula.objects.get(pk=1)
Designations.save()
return redirect('index')
Overriding the clean function on forms is probably where you want to put your logic. The django docs have a good example:
https://docs.djangoproject.com/en/2.0/ref/forms/validation/#cleaning-and-validating-fields-that-depend-on-each-other

Filtering a django-tables2 table with django-filters using a drop down list

I have a model (Brief) that i am showing in a list with Django-tables2. A Brief can belong to one or many towers. I am trying to create a view where a user can see all briefs, and then filter to find briefs related to a specific tower. I had first implemented this using check boxes, and it was working, but I need to get that filter into a drop down list.
"GET /brief/?towers= HTTP/1.1" - Gives me all the briefs.
"GET /brief/?towers=1 HTTP/1.1" - Gives an empty list of briefs.(should give me 2 in my test data)
Querying in django shell gives me the results I would expect.
Another odd behavior is that my drop down list has spaces that can be selected.
class Attribute(models.Model):
class Meta:
abstract = True
ordering = ['name']
name = models.CharField(max_length=100, unique=True)
created_on = models.DateTimeField(auto_now_add=True)
created_by = models.ForeignKey(User, related_name='%
(class)s_created_by', null=True, blank=True,
on_delete=models.SET_NULL)
modified_dt = models.DateTimeField(auto_now=True)
modified_by = models.ForeignKey(User, related_name='%
(class)s_modified_by', null=True, blank=True,
on_delete=models.SET_NULL)
def __str__(self):
return self.name
class Tower(Attribute):
pass
class Brief (Attribute):
link = models.URLField()
sources = models.ManyToManyField(SourceSystem)
format = models.ForeignKey(ReportFormat, on_delete=models.PROTECT)
towers = models.ManyToManyField(Tower)
type = models.ForeignKey(ReportType, on_delete=models.PROTECT)
project = models.ForeignKey(Project, on_delete=models.PROTECT)
def tower_list(self):
return ", ".join([str(obj) for obj in self.towers.all()])
def source_list(self):
return ", ".join([str(obj) for obj in self.sources.all()])
My tables.py:
class BriefTable(tables.Table):
name = tables.LinkColumn('brief_detail', args=[A('pk')])
class Meta:
model = Brief
template_name = 'django_tables2/bootstrap.html'
sequence = ('id', 'name', 'type', 'project', 'format',)
exclude = ('link', 'created_on', 'created_by', 'modified_dt', 'modified_by', 'info')
My filters.py
class BriefFilter(django_filters.FilterSet):
towers=django_filters.ModelMultipleChoiceFilter(
queryset=Tower.objects.all(), widget=forms.Select)
class Meta:
model = Brief
fields = ['towers']
my view:
class FilteredBriefListView(LoginRequiredMixin, SingleTableMixin,
FilterView):
table_class = BriefTable
template_name = 'brief/brief_list.html'
paginate_by = 20
filterset_class = BriefFilter
finally my route:
urlpatterns = [
path('', FilteredBriefListView.as_view(), name="home"),
]
After taking a little break I realized I'm using ModelMultipleChoiceFilter with a single choice instead of ModelChoiceFilter... /facepalm.

Django REST Framework many to many create and update

models.py:
class Book(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(max_length=500)
image = models.ImageField(height_field="height_field", width_field="width_field")
height_field = models.IntegerField(default=255)
width_field = models.IntegerField(default=255)
price = models.FloatField()
edition = models.CharField(max_length=100)
no_of_page = models.IntegerField()
country = models.CharField(max_length=50)
publication = models.ForeignKey(Publication, on_delete=models.CASCADE)
authors = models.ManyToManyField(Author, through='AuthorBook')
ratings = GenericRelation(Rating, related_query_name='books')
class AuthorBook(models.Model):
author = models.ForeignKey(Author, on_delete=models.CASCADE)
book = models.ForeignKey(Book, on_delete=models.CASCADE)
class Author(models.Model):
name = models.CharField(max_length=100)
biography = models.TextField(max_length=500)
image = models.ImageField(height_field="height_field", width_field="width_field")
height_field = models.IntegerField(default=255)
width_field = models.IntegerField(default=255)
serializers.py
class AuthorListSerializer(ModelSerializer):
url = author_detail_url
class Meta:
model = Author
fields = [
'url',
'id',
'name',
]
class BookCreateUpdateSerializer(ModelSerializer):
authors = AuthorListSerializer(many=True, read_only=True)
def create(self, validated_data):
#code
def update(self, instance, validated_data):
#code
class Meta:
model = Book
fields = [
'name',
'description',
'price',
'edition',
'no_of_page',
'country',
'publication',
'authors',
]
views.py
class BookCreateAPIView(CreateAPIView):
queryset = Book.objects.all()
serializer_class = BookCreateUpdateSerializer
I am working for implementing Django REST Framework. I have two models Book and Author. But django create api view don't show authors field drop down. I checked many solution DRF for many to many field. Please help me to show authors field and write create() and update function. If you see DRF api page, it will be clear.
This is because of read_only=True. Try to remove this argument for bookserializer's authors field:
class BookCreateUpdateSerializer(ModelSerializer):
authors = AuthorListSerializer(many=True)

Django Python 'Customer' object is not iterable

from django.db import models
class Customer(models.Model):
cust_firstname=models.TextField(max_length=50)
cust_lastname=models.TextField(max_length=50)
cust_company=models.TextField(max_length=100)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
cust_contact_number = models.IntegerField()
cust_email = models.TextField(max_length=100)
cust_address=models.TextField(max_length=200,default=None)
class Employee(models.Model):
employee_firstname = models.TextField(max_length=50)
employee_lastname = models.TextField(max_length=50)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
employee_contact_number = models.IntegerField()
employee_email = models.TextField(max_length=100)
employee_designation = models.TextField(max_length=50)
employee_address=models.TextField(max_length=200, default=None)
class ProjectDetails(models.Model):
customer = models.ForeignKey(Customer)
employee=models.ForeignKey(Employee)
project_name = models.TextField(max_length=50)
project_startdate = models.DateTimeField(auto_now=False, default=None)
project_status = models.TextField(default="Initial")
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
The above code is my model declaration
and my Serializer class is
from ProjectTemplate.models import Customer, Employee, ProjectDetails
from rest_framework import serializers
class CustomerSerializers(serializers.ModelSerializer):
class Meta:
model=Customer
fields = ('id','cust_firstname','cust_lastname','cust_company','created_at','updated_at','cust_contact','cust_email','cust_address')
read_only_fields = ('created_at', 'updated_at')
class EmployeeSerializer(serializers.ModelSerializer):
class Meta:
model=Employee
fields = ('id','employee_firstname','employee_lastname','created_at','updated_at','employee_contact','employee_email','employee_designation','employee_address')
read_only_fields = ('created_at', 'updated_at')
class ProjectDetailsSerializer(serializers.ModelSerializer):
customer = CustomerSerializers(many=True, read_only=True)
employee = EmployeeSerializer(many=True, read_only=True)
class Meta:
model = ProjectDetails
fields = ('id','project_name','project_startdate','created_at','updated_at','project_status','customer','employee')
read_only_fields = ('created_at', 'updated_at')
In my view i have the below code
def get(self, request, format=None):
queryset = ProjectDetails.objects.all()
projectid = self.request.query_params.get('pk', None)
if projectid is not None:
queryset = queryset.get(id=projectid)
serializer = ProjectDetailsSerializer(queryset, many=False)
return Response(serializer.data)
else:
serializer = ProjectDetailsSerializer(queryset, many=True)
return Response(serializer.data)
And my URL for the above view is
url(r'^api/v1/projects/$', ProjectListView.as_view()),
And when i try to access the URL on my Browser i get TypeError. Im trying to get all the Customers and Employees who belong to a project. But it fails can any one help me to fix this.
I'm trying to get all the Customers and Employees who belong to a project.
I am not sure what do you want to achieve here because looking at your model, an instance of ProjectDetail will only have one customer and one employee:
class ProjectDetails(models.Model):
customer = models.ForeignKey(Customer)
employee=models.ForeignKey(Employee)
Considering this, using many=True doesn't make any sense in the serializer. So this is what causing the error:
class ProjectDetailsSerializer(serializers.ModelSerializer):
customer = CustomerSerializers(many=True, read_only=True)
employee = EmployeeSerializer(many=True, read_only=True)
UPDATE: To show a specific field from the related object:
Based on the comments in the answer the OP want to show the name of customer or employee instead of id.
It can be achieved using a SlugRelatedField:
class ProjectDetailsSerializer(serializers.ModelSerializer):
customer = serializers.SlugRelatedField(slug_field='cust_firstname', read_only=True)
employee = serializers.SlugRelatedField(slug_field='employee_firstname ', read_only=True)
# other fields
Do note that using SlugRelatedField you can get only one field as in the example above you would get firstname for both.

Categories