about cacade foreignkey in django admin page - django

My model is like below:
class Manufacturers(models.Model):
name = models.CharField()
class Phones(models.Model):
manufacturer = models.ForeignKey(Manufacturers)
name = models.CharField()
class Prices(models.Model):
phone = models.ForeignKey(Phones)
price = models.DecimalFeild()
and I have registered them in the admin.py
My problem is:
In django's admin interface, When I add a price, I can select a phone from the dropdown list, But there are so many phones, So I want to select the manufacturer at first, then select the phone from the manufacturer's phones. How can I make this.
Thanks very much.

The term for this is "chained select menus".
There are a number of implementations in django. One that you may find useful is django-smart-selects.
Using django-smart-selects, this is how you would write up your models:
class Manufacturers(models.Model):
name = models.CharField()
class Phones(models.Model):
manufacturer = models.ForeignKey(Manufacturers)
name = models.CharField()
class Prices(models.Model):
phone = ChainedForeignKey(
Phone,
chained_field="manufacturer",
chained_model_field="manufacturer",
show_all=False,
auto_choose=True
)
price = models.DecimalField()
All that said, I wonder if you are implementing this in the best fashion.
It might be better to have Prices show up under the admin form for each phone. So instead of creating a price record and choosing the phone from a drop-down, you'd go into the record for that phone and add a price record. See django's documentation on InlineModelAdmin.

Related

Django admin: filter_horizontal with custom search/filter results

I have a simple model with ManyToManyField.
class Meeting(models.Model):
place = models.CharField()
date = models.DateField()
persons = models.ManyToManyField(Person)
Person model contains basic information about person.
class Person(models.Model):
login = models.CharField(unique=True)
first_name = models.CharField()
last_name = models.CharField()
def __str__(self):
return self.login
In my MeetingAdmin(ModelAdmin) class I have filter_horizontal('persons',) that is used for adding multiple people when creating new Meeting object. This works perfectly fine. In the left menu it's showing the list of all persons(filtering by login).
As you may know, filter_horizontal contains search box on the top of the left menu.
Examples
I would also like to be able to filter persons here by their first name and last name. For example, if there is a person with fields (login='mylogin', first_name='John', last_name='Smith') and I type 'Jo' or 'Smi' in search box, this person is displayed as a search result, etc. 'mylogin' since login field is representation of Person model.

How to retrieve related instances without FK using one query in django

Imagine there are three models named Movie, Actor, and Participation.
class Movie(models.Model):
identifier = models.CharField()
class Actor(models.Model):
name = models.CharField()
class Participation(models.Model):
movie_identifier = models.CharField()
actor = models.ForgeinKey(Actor, on_delete=models.CASCADE)
Let's assume that I can't use ForgeinKey for the movie in the Participation model.
how can I retrieve all the participation records of a movie with only one query?
Here is the solution if I had a foreign key for the movie in the participation table:
qs = Movie.objects.filter(identifier="an_identiier").prefetch_related("participations_set")
How can I do this without having a Movie foreign key in the Participation model?
Thanks!
One of the most important things when designing a database (hence when designing your models) is database normalization [Wikipedia].
You talk about Participation being related to multiple models like Movie, Series, Episode, etc. this means that Movie, Series, Episode all can be said to have something in common or they can be said to be a specialization of another entity let us say Participatable for the lack of a better word, or we can say Participatable is a generalization of Movie, Series, Episode, etc.
How do we model these? Well we will just have an extra model that our other models will have a OneToOneField with:
class Participatable(models.Model):
# Any common fields here
MOVIE = 'M'
SERIES = 'S'
TYPE_CHOICES = [
(MOVIE, 'Movie'),
(SERIES, 'Series'),
]
subject = models.CharField(max_length=1, choices=TYPE_CHOICES)
class Movie(models.Model):
# uncommon fields
participatable = models.OneToOneField(
Participatable,
on_delete=models.CASCADE,
related_name='movie',
)
class Series(models.Model):
# uncommon fields
participatable = models.OneToOneField(
Participatable,
on_delete=models.CASCADE,
related_name='series',
)
class Participation(models.Model):
participatable = models.ForgeinKey(Participatable, on_delete=models.CASCADE)
actor = models.ForgeinKey(Actor, on_delete=models.CASCADE)
Other than this solution which I find is the best for such modelling you can go with using the content-types framework which will essentially do what you do currently. That is it will use a field that stores the related id and also a foreign key that points to an entry in a table that will simply describe which table this id is for.

Manytomany django using existing key

I hope this is not a duplicate question. I am trying to setup models in django.
In model 1 I have one kind items (parts), these can together form item type 2 (car).
I get the prices for all of these from outside interface to a model prices.
How can I setup the relationship between price - > part and price - > car.
I do not know when I get the prices if the ident belongs to car och part.
class parts(models.Model):
ident = models.CharField("IDENT", max_length = 12, unique = True, primary_key = True)
name = models.CharField(max_length=30)
class car(models.Model):
ident = models.CharField("IDENT", max_length = 12, unique = True)
start_date = models.DateField()
end_date = models.DateField()
parts= models.ManyToManyField(parts)
class Prices(models.Model):
ident= models.CharField(max_length=12)
price = models.DecimalField(max_digits=10, decimal_places= 4)
date = models.DateField()
def __unicode__(self):
return self.ident
class Meta:
unique_together = (("ident", "date"),)
I would imagine you would not store price in your model since you need this to be 100% real time. So you have;
car models.py
from parts.models import parts
name = models.CharField(max_length=100)
parts = models.ManyToManyField(parts)
Hopefully you're not trying to develop like a full scale autozone type deal, but if it's simply a car model object that is comprised of many parts than this is the basic setup you would want. having the many to many relationship to parts allows one car to have many parts. parts can belong to many cars. You don't have to specify a manytomany relationship in the parts model as the two way communication will already be handled in your cars model.
As far as price is concerned you could have a price database field in your parts model, but once again if this needs to be real time, you probably want to request that price via an api and display it directly in your webpage.

limit_choices_to in DjangoAdmin

One of my models contains a ForeignKey-field to a model that has multiple thousand instances.
When I display a record, all of these are loaded into a dropdown, which I a) don't need and b) is slow as frack, especially when displaying multiple records on one page.
Page size shoots up to multiples of 3.5mb because of the size of the dropdown.
I thought about using "limit_choices_to" to contain that, but
country = models.IntegerField(blank=True, null=True)
location = models.ForeignKey(Geonames, limit_choices_to = {'cowcode': country}, related_name='events')
does not work.
Is there even a way to do that?
Update:
What do I want to display?
I want to show all places (Geonames) that are in the country of the EventRecord that the code above is taken from. I want to show only these places, not the whole list of all possible places.
Why don't I need all places?
a) Page load times: 3.5 minutes for a page load is a tad too long
b) See above: An Event takes place in a certain country, so I don't need to show locations that are not in that country
What you want is to make limit_choices_to aware to your instance, which is not possible.
What you should do is set the queryset property of location field in your admin form, something similar to this:
class EventRecordAdminForm(forms.ModelForm):
class Meta:
model = EventRecord
def __init__(self, *args, **kwargs):
super(EventRecordAdminForm, self).__init__(*args, **kwargs)
self.fields['location'].queryset = Geonames.objects.filter(cowcode=self.instance.country)
and of course use that form for your admin:
class EventRecordAdmin(admin.ModelAdmin):
form = EventRecordAdminForm
See here for docs
HTH!
if you are using admin interface you can use raw_id_fields in ModelAdmin:
class BookAdmin(admin.ModelAdmin):
list_display = ('title', 'publisher', 'publication_date')
list_filter = ('publication_date',)
date_hierarchy = 'publication_date'
ordering = ('-publication_date',)
filter_horizontal = ('authors',)
raw_id_fields = ('publisher',)
from Django Book:
sometimes you don’t want to incur the overhead of having to select all the related objects to display in the drop-down. For example, if our book database grows to include thousands of publishers, the “Add book” form could take a while to load, because it would have to load every publisher for display in the box.
The way to fix this is to use an option called raw_id_fields. Set this to a tuple of ForeignKey field names, and those fields will be displayed in the admin with a simple text input box () instead of a select.
Not sure why that is not working for you. But I think a better solution would be to use django-smart-selects. That way you can have the user choose country first. Then the Geoname dropdown is only populated when the user first chooses country.
From the docs:
If you have the following model:
class Location(models.Model)
continent = models.ForeignKey(Continent)
country = models.ForeignKey(Country)
area = models.ForeignKey(Area)
city = models.CharField(max_length=50)
street = models.CharField(max_length=100)
And you want that if you select a continent only the countries are available that are located on this continent and the same for areas you can do the following:
from smart_selects.db_fields import ChainedForeignKey
class Location(models.Model)
continent = models.ForeignKey(Continent)
country = ChainedForeignKey(
Country,
chained_field="continent",
chained_model_field="continent",
show_all=False,
auto_choose=True
)
area = ChainedForeignKey(Area, chained_field="country", chained_model_field="country")
city = models.CharField(max_length=50)
street = models.CharField(max_length=100)
This example asumes that the Country Model has a continent = ForeignKey(Continent) field and that the Area model has country = ForeignKey(Country) field.

Django modeling with filmography

I'm still a beginner in django, and I'm working on a small project.
Lets say I have a list full of actors/actresses along what films they've been in. I also have another list of films with specific details of the film such as date of release, casts, credits etc.
The main goal of the app is to be able to search a specific person and pull up the details of all their films.
So for the models right now I have:
class Person(models.Model):
name = models.TextField()
class Film(models.Model):
name = models.TextField()
year = models.IntegerField
The Film model will have a lot more information, but I'm not exactly sure how to link the two. For example I want a user to be able type in "Tom Hanks" and then have the details for his 5 most recent movies displayed.
So for the Person model should I add some field that has a list of their films as foreign key somehow, or is there a better way?
Thanks for the help.
models.py
class Person(models.Model):
name = models.TextField()
class Film(models.Model):
name = models.TextField()
year = models.IntegerField()
actors = models.ManyToManyField('Person')
and then access the film actors using the following command
#first get the film from db
f = Film.objects.all()[0] #get the first Film entry
actors = f.actors.all()