Django admin search and edit foreign fields - python

I've got a two part question regarding Django Admin.
Firstly, I've got a Django model Classified that has a foreign key field from another table Address. On setting data, I've got no issues with any of the fields and all fields get saved correctly.
However, if I want to edit the foreign field in the entry in Classified, it doesn't display the old/existing data in the fields. Instead it shows empty fields in the popup that opens.
How do I get the fields to display the existing data on clicking the + so that I can edit the correct information?
Secondly, I'm sure I've seen search fields in Django Admin. Am I mistaken? Is there a way for me to implement search in the admin panel? I have over 2 million records which need to be updated deleted from time to time. It's very cumbersome to manually go through all the pages in the admin and delete or edit those.
Adding Model Code:
Classified
class Classified(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=256)
contact_person = models.CharField(max_length=300, blank=True)
email = models.CharField(max_length=100, blank=True)
address = models.ForeignKey(Address)
subcategory = models.ForeignKey(Subcategory)
Address
class Address(models.Model):
id = models.AutoField(primary_key=True)
build_add = models.CharField(max_length=255)
street_add = models.CharField(max_length=255)
area = models.CharField(max_length=255)
city = models.ForeignKey(Cities)

The + means just that - add a new instance of the related object and relate the object you're editing to that. Because you're adding a new object it will be blank to start. If you want to be able to edit existing related objects from another object's admin you need to use inlines.
In your app's admin.py have something like:
from django.contrib import admin
from yourapp.models import Address, Classified
class AddressInline(admin.TabularInline):
model = Address
class ClassifiedAdmin(admin.ModelAdmin):
inlines = [AddressInline,]
admin.site.register(Classified, ClassifiedAdmin)
Adding search from there is really easy.
...
class ClassifiedAdmin(admin.ModelAdmin):
inlines = [AddressInline,]
search_fields = [
'field_you_want_to_search',
'another_field',
'address__field_on_relation',
]
...
Note the double underscore in that last one. That means you can search based on values in related objects' fields.
EDIT: This answer is right in that your foreignkey relationship is the wrong way round to do it this way - with the models shown in your question Classified would be the inline and Address the primary model.

Related

Django Admin Change View is stuck because of __str__ method of related field

I have this model in accounts.models:
from django.contrib.auth.models import User
class UserProfile(BaseModel):
user = models.OneToOneField(
User, related_name="user_profile", on_delete=models.CASCADE
)
# ...
def __str__(self) --> str:
return self.user.username
And the following in memberships.models:
class ExternalServiceProfileMembership(BaseModel):
created_at = models.DateTimeField()
expires_at = models.DateTimeField()
profile = models.ForeignKey(
"accounts.UserProfile",
on_delete=models.CASCADE,
related_name="ext_memberships",
)
plan = models.ForeignKey("memberships.MembershipPlan", on_delete=models.CASCADE)
ext_subscription_id = models.CharField(max_length=128)
When I try to access the admin view of an individual ExternalServiceProfileMembership object (for example: http://localhost:8000/admin/memberships/externalserviceprofilemembership/1/change/), the site gets stuck, eventually returning a 503. So I started out commenting out fields in the AdminModel, and once I remove profile, the object change view loaded fine.
I brought back profile into AdminModel but removed UserProfile's __str__() method, and it also worked. Which makes me think the whole issue is with this method; but I have no idea why.
Any help is appreciated!
On the change page for ExternalServiceProfileMembership, the profile dropdown displays the name of every user. This causes one extra query for every user in the dropdown.
The quick fix is to add 'profile' to readonly_fields, autocomplete_fields or raw_id_fields. These three options mean that a single profile is displayed on the change form, so there is only one extra query to fetch the user.
Another approach, which is more complicated, is to create a custom form that overrides the queryset to use select_related to fetch all of the users, then use that form in your model admin.

Django admin limit model from foreign key

I have the following model setup:
The problem is that when I try to pull the object up in the admin page, computer_names links to several hundred thousand rows that aren't relevant and the page never loads. How can I filter computer_names to only the user selected objects for the ManyToMany field?
class ScoringException(models.Model):
class Meta:
ordering = ['date_modified']
requester = models.CharField('Requester',max_length=50,null=False,blank=False)
computer_names = models.ManyToManyField(Computer)
domain = models.ForeignKey(Domain)
exception_kpi_types = models.ManyToManyField(ScoringType)
expiration_date = models.DateField('Expiration Date')
reason = models.CharField('Reason',max_length=1000,null=False,blank=False)
approved = models.BooleanField('Approved')
date_modified = models.DateTimeField('Date Updated',auto_now=True)
You can use raw_id_fields in the admin so that Django doesn't render the hundred thousand rows of data:
#admin.register(ScoringException)
class ScoringExceptionAdmin(admin.ModelAdmin):
....
raw_id_fields = ['computer_names']
With raw_id_fields, Django will display the list of ids for selected m2m objects. A search button is also added to make adding new objects for the m2m relationship easier.
See the documentation for more information.

Django admin inline-model customization

Is there a way to de-couple django admin inline-models from clustering like models together?
A bit of context: I have a model named Page with two inline-models, TextBlock and GalleryContainer. I would to render TextBlocks and GalleryContainers on a template based on the order they're added in the Page admin editor. The default django-admin display looks like this:
I would like it to display as:
Gallery Container 1
Textblock 1
Gallery Container 2
But I have no idea how to do that. Any suggestions or nudges in the right direction would be a great help. Thanks in advance. (I also hope my question makes sense...)
If you want a relation between a column and a gallery your models should reflect that. So if I understand correctly: A page has name and columns. A column has text, gallery (optional) and ordering.
models.py:
class Page(models.Model):
name = models.CharField(max_length=200)
class Gallery(models.Model):
name = models.CharField(max_length=200)
class Column(models.Model):
page = models.ForeignKey(Page)
text = models.TextField()
gallery = models.ForeignKey(Gallery, null=True, blank=True) # Optional
ordering = models.IntegerField()
class Meta:
ordering = ('ordering', )
This example shows how ordering is done by an IntegerField. If you want to order the columns based on the moment they where added replace
ordering = models.IntegerField()
with
models.datetimeField(auto_now_add=True)
In your admin.py:
class ColumnInline(admin.TabularInline): # or StackedInline
model = Column
class PageAdmin(admin.ModelAdmin):
inlines = [
ColumnInline,
]
Note: I put your 'gallery display name' in Gallery as 'name'. Makes more sense to give the gallery it's name only once. But if a gallery is in more places with different names, than you need a field (e.g. 'gallery_display_name=models.CharField(max_lenght=200)') on the Column model.
Is this the answer to your question? I hope it helps!

Django - complex forms with multiple models

Django 1.1
models.py:
class Property(models.Model):
name = models.CharField()
addr = models.CharField()
phone = models.CharField()
etc....
class PropertyComment(models.Model):
user = models.ForeignKey(User)
prop = models.ForeignKey(Property)
text = models.TextField()
etc...
I have a form which needs to display several entries from my Property model each with a corresponding PropertyComment form to collect a user's comments on that property. In other words, allowing a User to comment on multiple Property instances on the same page.
This seems outside the intended usage of an Inline formset since it is multi-model to multi-model vs. single-model to multi-model. It seems like trying to iterate through the Property instances and create an inline formset for each is not only clunky, but I'm not even sure it could work.
Any ideas on where to start on this?
Have you thought about using the comment framework:
http://docs.djangoproject.com/en/dev/ref/contrib/comments/
If that doesnt work for you then maybe look into inlineformset_factory:
http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#inline-formsets
from django.forms.models import inlineformset_factory
PropertyCommentFormSet = inlineformset_factory(Property, PropertyComment)
property= Property.objects.get(name=u'some property name')
formset = PropertyCommentFormSet(instance=property)
etc...

Django import problem with models.py and multiple ManyToManyFields()

I am working on creating a simple contest submission system using django. This is my first real django project. Basically each user can view a list of problems, submit a file, and view a results page.
Each problem can be associated with multiple contests, and different contests can use the same problem. Because of this, both problem and contest have a manyToManyField with each other. This is what is causing my problem.
Here is the initial models.py implementation I am going with:
startfile
from django.db import models
class User(models.Model):
username = models.CharField(max_length=50)
firstname = models.CharField(max_length=50)
lastname = models.CharField(max_length=50)
class Problem(models.Model):
name = models.CharField(max_length=50)
filename = models.CharField(max_length=300)
contests = models.ManyToManyField(Contest)
class Contest(models.Model):
name = models.CharField(max_length=50)
problems = models.ManyToManyField(Problem)
date = models.DateField()
class Submission(models.Model):
user = models.ForeignKey(User)
problem = models.ForeignKey(Problem)
filename = models.CharField(max_length=300)
endfile
Is there a simple way to fix this? Or should I rethink my entire layout? I tried breaking each class into its own django app but I don't think thats how I should do it. The error I get is that Contest can not be found (because it exists lower in the file).
All advice is appreciated!
You don't need a ManyToManyField in both Contest and Problem. Many-to-many fields are already bidirectional. Just put it on one - doesn't matter which.
Djano will automatically create the reverse relation for you, so you only need to create it one end, eg.
class Problem(models.Model):
name = models.CharField(max_length=50)
filename = models.CharField(max_length=300)
contests = models.ManyToManyField(Contest, related_name='problems')
related_name gives you the possibility to assign a name to the reverse relation. Without defining the relation on the Contest model, you can then access eg. a_contest.problems.all()!

Categories

Resources