Tracking a reverse relationship for a foreignkey in django-reversion - django

I'm trying to figure out how how to track changes for a foreignkey relationship in Django using Django-reversion.
In short, I am trying to model a Codelist, which contains Codes which only belong to one Codelist. This can be modelled using a foreign key like so:
class CodeList(models.Model):
name = models.CharField(max_length=100)
class Code(models.Model):
value = models.PositiveIntegerField(max_length=100)
meaning = models.CharField(max_length=100)
codelist = models.ForeignKey(CodeList,related_name="codes")
Additionally, the only way to edit a code is by using an inline form in the admin site accessed via its codelist. For all intents and purposes, codes belong to codelists as they should...
Except when it comes to reversion.
I'm using the reversion.middleware.RevisionMiddleware to track all editing changes, as there are some non-admin forms for editing codes.
What I'd like is when I see the history of a codelist, it should changes to the codes as well, but I can't figure that out in the Django-reversion API. The issue is that the API covers tracking the code, and seeing changes to the codelist, not the other way around by following the reversed relationship.
Is anyone aware of how this might be done?

Its not well documented Its very well documented, I just couldn't find it, but you can just add the inverse relationship as the field to follow like so:
reversion.register(CodeList, follow=["codes"])

Related

how can i replicate admin.TabularInline outside of the admin (on the user side?)

Given a mode A and a model B that has a field with a many to many relationship with model A, I am trying to allow users creating an object of model B to also create an object of model A inline/on-the-fly just like TabularInline allows you to do on the admin.
This is a very common problem and the solution is not trivial (at least for the moment). Django admin uses Javascript(jQuery) to do this task. Multiplication of a form requires lots of altering values and IDs etc. But recently people started doing this with htmx. The way it is done is explained in this article from JustDjango thoroughly. There is even a video tutorial about it. I personally like the way they do it. You can give it a try. It feels and looks like in the django admin. If you would like to do it purely in django, you can look up formset_factory

Can I make Django admin reflect a hierarchy of models?

Assume a Django application with a few models connected by one-to-many relationships:
class Blog(models.Model):
...
class Post(models.Model):
blog = models.ForeignKey(Blog)
...
class Comment(models.Model):
post = models.ForeignKey(Post)
...
Conceptually, they form a hierarchy, a tree-like structure. I want the Django admin to reflect that. In particular:
in a changelist of posts, every post should have a link to the changelist of corresponding comments;
similarly, a post’s edit page should link to the changelist of comments from the top-right buttons area;
when I open that list of related comments, it needs to reflect the relationship in the breadcrumbs (something like: Posts › “Hello world” › Comments) and, ideally, also in the URL (post/123/comment/).
This should of course also apply to the other levels of the hierarchy.
Number 1 is pretty easy with a custom list_display entry and using the ?post__id= query to the comments changelist. But this is little more than a hack. Generally Django assumes my three models to be independent, top-level entities.
Is there a straightforward way to accomplish this? I guess I could override a bunch of templates and AdminModel methods, but perhaps there is a better solution for what seems like a common situation?
Are you sure you are not just looking at Django Admin Inline Models ?
There is no way that an automated admin will pick up your relationships, because in an RDBS there can be any number of foreign keys / one to one / many to many relations, and Django does not have a customized hierarchical behavior built in.
You can indeed edit the breadcrumb customizing an admin template if you want.
For relations you might also be interested into django MPTT that allows to make hierarchical model instances. Also see this question: Creating efficient database queries for hierarchical models (django) in that respect.
How is this a common situation? Consider the fact a model can have a virtually unlimited number of foreign key relationships, let alone visa versa. How would the admin 'know' how to represent this data the way a user requires without customizing things?
One would suggest you are used to work with content management systems rather than webframeworks (no pun intended). It's important to notice Django isn't a cms, but a webframework you can built on top of as you see fit. In a nutshell: 'Django is rather clueless and unaware of contextual requirements'.
Although the admin is quite a beast out-of-the-box, it can be hard to customize. There have been quite some discussions whether it should even be part of core. I can only suggest, if customizing things tends to get hacky, you should probably write your own 'admin', it's not that hard.

Creating Dynamic Forms in Django

I'm working on a project that involves a form with some standard fields and some custom field users define later. The standard forms are defined on a model in models.py. For example:
class Order(models.model):
number = models.TextField()
date = models.DateField()
I then use this model to create a simple model form to make a way to fill in the information. That's pretty standard Django.
The tricky thing is that my users want to be able to add arbitrary fields to the form. They would like to be able to use the Admin interface to basically modify the form and add values to it at run time.
So, they might want a new text field called "Tracking Number" or something like that. The trick is that they only need it sometimes and they want to be able to add it dynamically without rebuilding the whole database.
I can create a fairly simple model to represent the custom fields like so:
class CustomField(models.Model):
type = models.CharField(choices=FIELD_TYPES)
required = models.BooleanField()
I think I can then take the ModelForm for the Order class and extend it to add these custom fields. What I am unsure of is how to link the custom field values back to the Order.
I know this all might sound odd, but in practice it makes sense. Each user has slightly different needs for the form and want to tweak it. If I have to hard code the models to have their specific fields, then I will have to have a fork for each user. That simply doesn't scale. If instead they can simply add the fields through the admin interface, then things are much simpler.
I feel like this is something that is perhaps already solved by someone out there. I simply cannot find a solution. I can't be the only one who has gotten this kind of request right?

Extending a field of a contrib model in Django

I have come across this situation several times.
If I have something that I generally like in contrib, but I want to make one minor tweak to a field, what do I do?
I don't want to throw out the baby with the bathwater.
To give an example, take auth.user (which, contrary to what seems to be popular opinion on the matter, I regard as being generally on the right track). I want to create a through model for auth.user's relationship to auth.group.
How can I do this without modifying django?
auth.User is a special case since the User model is tied in to lots of parts of Django and it is tricky to modify this (though not impossible, as others have pointed out). My best advice would be to question why you don't want to modify Django source. You can pull source for either the head of the devel branch or get a tagged version corresponding to a numbered release. Modify the code at will and use some combination of svn update, svn diff, and svn patch to migrate your changes.
Next, modifications to contrib modules are possible in your code, since Python is interpreted and dynamically typed. If you do this, you'll need to take into consideration parsing/processing order since some operations may already have utilized the original module. Below is an example I got from someone else (probably here on SO) of how to add a convenient forward reference from User to the associated Profile object:
from django.db.models import Model
from django.contrib.auth.models import User
class UserProfile(Model):
user = ForeignKey(User, unique=True)
phone = CharField(verbose_name="phone number", blank=False, max_length='20')
User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])
I don't think this strategy will work for adding/modifying ModelFields in django.contrib.auth.models.User, however.
Finally, for your specific example of associating groups with a user, you should see if this is possible by creating a UserProfile model. My initial guess is that it should be pretty easy.

Django: "reverse" many-to-many relationships on forms

The easiest example of the sort of relationship I'm talking about is that between Django's Users and Groups. The User table has a ManyToMany field as part of its definition and the Group table is the "reverse" side.
A note about my constraints: I am not working with the Admin interface at all nor is that an option.
Now, onto the programming problem. I need to write a form that is used to edit MyGroup instances, defined simply as the following:
class MyGroup( Group ):
some_field = models.CharField( max_length=50 )
I want to be able to have a form page where I can edit both some_field and which users are members of the group. Because I'm working with a model, a ModelForm seems obvious. But I cannot figure out how to get Django to include the users because it is on the reverse side of the User-Group relationship. Ideally, I'd like the display widget for specifying the users to be like the one for specifying permissions that is found on the User and Group pages within Admin.
inline-formsets
do the trick for a foreign key relationship.
GroupUserInlineFormSet = inlineformset_factory(MyGroup, User, form=PurchaseOrderEditForm, max_num=100, extra=2, can_delete=False)
guformset = GroupUserInlineFormSet (instance=mygroup)
might point you in the right direction. not sure how this can work with a manytomany relationship.
I never found a great way to do this. I ended up writing custom forms that manage creating the fields and specifying an appropriate queryset on them.
For the display portion of the question, there is a way to use the SelectFilter (a.k.a. horizontal filter) on regular pages. One page with instructions I found is here, and there was another that was helpful, but I can't seem to re-located it.
I'm considering writing up a more thorough guide to both parts of this process. If anyone is interested please let me know, it'll give me the push to actually get it done.