I searched and could not find a way to do this. Here's my situation:
I have 3 classes:
Publication
Person
AuthorOrder
The last is a through class that allows me to specify the author order for a publication, as this does not normally seem possible to do.
Initially, I made Author a mandatory field (blank=False) for Publication and added a placeholder Person object to add Publications to that don't have a proper author. However, a better solution seems to be to just handle missing authors in Views appropriately. Now, I've changed the field to be optional, but I cannot seem to set the authors to empty via the admin panel. It gives me a "This field is required." error. My guess is that this is because the Person is required of the through class, but setting the Person to null/empty in the admin panel does not set the through object to null/empty.
I found a workaround. One can delete the placeholder Person object. This unsets the through class from the Publications without deleting them via cascade as they are no longer mandatory. However, this is not always a good workaround, so I hope there's a better method.
models.py
There is a lot of code, I reproduce only the minimal necessary:
#Publication
class Publication(models.Model):
authors = models.ManyToManyField(Person, blank=True, related_name="author_of", through='AuthorOrder')
#Person
class Person(models.Model):
# mandatory
firstname = models.CharField(max_length=200)
# AuthorOrder
class AuthorOrder(models.Model):
publication = models.ForeignKey(Publication)
author = models.ForeignKey(Person)
admin.py
# AuthorInline
class AuthorInline(admin.StackedInline):
model = AuthorOrder
extra = 3
# Publication
class PublicationAdmin(admin.ModelAdmin):
list_display = ("title", 'issue', "keywords")
search_fields = ['title', "keywords"]
list_filter = ['issue']
# author list via Inline
inlines = [AuthorInline]
admin.site.register(Publication, PublicationAdmin)
It's simple. To the very right of the "Author order: AuthorOrder object" line, there is a small "Delete" box. Check it and save. It's small and somewhat oddly placed, so easily gets missed.
Related
I am little bit comfused. Lets say I have such models.
models.py:
class Company(models.Model):
name = models.CharField(blank=False, null=False)
class Game(models.Model):
developer = models.ForeignKey(Company, on_delete=models.CASCADE)
publishers = models.ManyToManyField(Company)
If I use next code:
current_company = Company.object.get(pk=1)
current_company.game_set.all()
as I understand it return all games of current_company, but what field (developer or publishers) Django used?
But this code wouldn't be valid, for precisely this reason. If you tried to run it, Django would tell you that there was a conflict in the reverse relation.
If you have two relationships pointing to the same model, you need to explicitly set related_name on one of them to avoid this conflict.
I have multiple databases with different relations and I'm unable to figure out how to properly structure things to avoid problems in Django Admin.
Here is the design I want:
Category
-> 'name' (CharField)
Movie
-> Multiple CharFields
CategoryLink
-> 'category' (ForeignKey -> Category)
-> 'movie' (ForeignKey -> Movie)
-> 'prefix' (ForeignKey -> Prefix) - Blank, Null
-> 'number' (DecimalField)
Prefix
-> 'category' (ForeignKey -> Category)
-> 'prefix' (CharField)
I want to achieve is a structure where:
Each Category can have multiple CategoryLinks to Movies
Movies can exist within any number of Categories any number of times.
CategoryLinks can have a Prefix, but doesn't have to have one.
Prefixes are limited to specific Categories
Editing a Prefix for a specific Category has no effect on a prefix of the same name for a differ Category
Categories can have multiple or zero Prefixes
Prefixes can only be used by a CategoryLink if the Prefix.category == CategoryLink.category
Unrelated Prefixes are hidden from Categories
My main issue is that when I try to limit the choices of Prefixes to only display choices relevant to the current Category I run into a wall. I can do it fine when editing a CategoryLink, but not when adding a new one.
If I try to limit the choices in the Admin Panel with something like this:
#admin.py
# ....
def __init__(self, *args, **kwargs):
super(PrefixForm, self).__init__(*args, **kwargs)
Prefix.objects.filter(category_id=self.instance.category.id)
It works fine while editing, but it throws an error whenever I'm in a form which has the ability to add new entries. Since the new entries doesn't have a defined category.id by virtue (I assume) of not existing yet Django throw an "RelatedObjectDoesNotExist" exception at me.
If I can get it to work while editing an existing Category that would be fine. I don't need to be able to create new CategoryLinks without having a Category already, but when I try I get the same error since I'm using a TabularInline class to include CategoryLinks into Category.
I'm willing to completely restructure everything to get this to work, as you can probably tell I'm new to Django so it's possible I'm thinking about this all wrong.
I asked a similar question last week that I thought I had figured out on my own, but it turned out I simply pushed the problem a step rather than solve it.
Is there a better way to structure my models or is there something I can do within admin.py to properly filter prefixes to categories? Let me know if you want to see all my code, it seemed a bit too much to post here.
I could "solve" this issue by turning CategoryLink.prefix into a CharField, but it would be so much cooler if I could have a separate model for Prefixes.
Here is my full Model.py (minus some irrelevant __unicode__ stuff)
from django.db import models
class Category(models.Model):
class Meta:
verbose_name_plural = "Categories"
name = models.CharField(max_length=255, unique=True)
def category_link_count(self):
return len(CategoryLink.objects.filter(category_id=self.id))
category_link_count.short_description = 'Movies in Category'
class Movie(models.Model):
title = models.CharField(verbose_name='Movie Title', max_length=300)
year = models.DecimalField(verbose_name='Year of Release',
max_digits=4, decimal_places=0)
class CategoryLink(models.Model):
class Meta:
verbose_name = "Category Link"
verbose_name_plural = "Category Links"
category = models.ForeignKey(Category)
movie = models.ForeignKey(Movie)
prefix = models.ForeignKey('Prefix', blank=True, null=True)
number = models.DecimalField(verbose_name='Movie Number', max_digits=2,
blank=True, null=True, decimal_places=0)
class Prefix(models.Model):
category = models.ForeignKey(Category)
prefix = models.CharField(verbose_name='Category Prefix', max_length=255)
class Meta:
verbose_name = "Prefix"
verbose_name_plural = "Prefixes"
ordering = ['-category']
My suggestion is to have defaults for fields that have relations with other models, that way you can create a a Category and have an arbitrary Prefix. However, I think you have structured your models inappropriately.
Category has a ManyToManyField to Prefix which has a FK to Category. You don't need the FK. This is just one, but you can really simplify your organization. I don't know enough about what you want to accomplish.
I have a model for universities and another for contacts:
class University(models.Model):
abbrev = models.CharField(max_length=20, unique=True) # example "ASU" for Alabama State University
name = models.CharField(max_length=512, unique=True)
city = models.CharField(max_length=512)
state = models.CharField(max_length=2, choices=STATE_CHOICES) # abbreviation
region = models.CharField(max_length=2, choices=REGION_CHOICES) # examples Mid West, South Coast, etc.
type = models.CharField(max_length=3, choices=TIPO_IES_CHOICES) # public, private, etc.
class UniversityContact(models.Model):
person ...
university ... # models.OneToOneField("University") ???
When editing UniversityContact on the admin interface, I would like to be able to "pull" 'abbrev', 'state', 'region', and 'type' from University to show together with the contact info. Is that possible? They don't have to be editable from that context.
I've tried adding those fields to UniversityContact, all as "models.OneToOneField("University", related_name='...')", but they all end up showing the same value - abbrev - from the other table.
I'd like to be able to quickly sort contacts by, say, region, etc.
Displaying is easy - define a method that returns the related data on the model or the admin class, then use the method in list_display and/or readonly_fields.
For sorting, define the admin_order_field property of the method. Although list_display and readonly_fields do not support the double underscore related field syntax, admin_order_field does. So something like this:
class UniversityContact(models.Model):
# as above, plus:
def abbrev(self):
return self.university.abbrev
abbrev.admin_order_field = 'university__abbrev'
Optionally you can set the short_description attribute as well, if you don't want the default choic of the method name:
abbrev.short_description = 'abbreviation'
You didn't ask about this, but it seems worth knowing - list_filter also supports the standard related field name syntax:
list_filter = ('university__region',)
Alternatively, there's a code snippet here that claims to address it:
http://djangosnippets.org/snippets/2887/
I haven't tested that myself.
I have a Django application with following class:
class Opinion(models.Model):
id = models.AutoField(primary_key=True)
contents = models.CharField(max_length=256)
source = models.CharField(max_length=256)
proArguments = models.ManyToManyField('self', verbose_name="Pro arguments", related_name='proargs', null='true', blank='true')
contraArguments = models.ManyToManyField('self', verbose_name="Contra arguments", related_name='contraarg', null='true', blank='true')
def __unicode__(self):
return self.contents
When I try to create a new instance of this class in the admin, the newly created opinion has one proArgument and one contraArgument, even though I didn't enter them.
What can I do in order for proargs and contraarg to be empty, when I don't enter them?
The multiple select widget for both many to many fields contains all possible Opinions. In your screenshot, there are no Opinions selected for these fields. They are not selected until you click on one or more opinions and save.
You might find the filter_horizontal and filter_vertical model admin options helpful. They make it clearer which objects are selected.
I'm looking to implement a zipcode field in django using the form objects from localflavor, but not quite getting them to work. I want to have a zipcode field in a form (or ModelForm in my case), but the fields never validate as a zipcode when calling _get_errors() on the form object. The way I'm implementing it seems right to me but is apparently wrong, does anyone know what the right way to do this might be?
I have a ModelForm that I want to use zipcode (and also USStateField) in:
from django.contrib.localflavor.us.forms import USStateField
from django.contrib.localflavor.us.forms import USZipCodeField
class FooForm(ModelForm):
class Meta:
model = Bar
fields = ('address', #This form uses a subset of fields from the model
'address_apt',
'address_city',
'address_state',
'address_zip',
'home_phone',
'mobile_phone')
widgets= {
'address_zip' : USZipCodeField(),
'address_state' : USStateField(),
}
The ModelForm 'FooForm' links to a model that looks like:
from django.contrib.localflavor.us import models as usmodels
class Bar(models.Model):
db_table = 'BAR'
address = models.CharField(max_length=255)
address_apt = models.CharField(max_length=40, blank=True)
address_city = models.CharField(max_length=90)
address_state = usmodels.USStateField()
address_zip = models.CharField(max_length=15)
home_phone = usmodels.PhoneNumberField( )
mobile_phone = usmodels.PhoneNumberField( )
#... There are more fields in the model...
But if I create an instance of the form and run it's validation, it never cares about the form level validation, only the model level validation:
foo_instance = FooForm(request.POST)
#Let's assume request.POST looks like:
#<QueryDict: {u'address_city': [u'asdf'], u'mobile_phone': [u'asdf'], u'address_state': [u'California'], u'home_phone': [u'asdf'], [u'1'], u'address': [u'123 foo'], u'address_zip': [u'asdf']}>
foo_instance._get_errors()
Yields:
<ul class="errorlist">
<li>mobile_phone<ul class="errorlist">
<li>Phone numbers must be in XXX-XXX-XXXX format.</li></ul>
</li><li>home_phone<ul class="errorlist">
<li>Phone numbers must be in XXX-XXX-XXXX format.</li></ul>
</li></ul>
I need to be able to call validation on the populated form object and have it tell me that the zipcode is formated improperly if so. Doing something wrong, just don't know what atm.
Using widgets declaratively has literally only just been added to the trunk SVN version in the last day or so. If you're using an older checkout, or a released version, it won't work - you'll need to go back to the old way of doing it, by overriding the field declarations at the top level of the form.