Using two models in one form in django 1.5 - python

How can I use two models with OneToOne relation in one form using the CreateView in Django 1.5?
My models are these:
class Act(models.Model):
name = models.CharField()
class DetailAct(models.Model):
detail = models.CharField()
act = models.OneToOneField(Act)
My forms
class ActForm(forms.ModelForm):
name = forms.CharField(widget=forms.TextInput())
class Meta:
model = models.Act
class DetailActForm(forms.ModelForm):
detail = forms.CharField(widget=forms.TextInput())
class Meta:
model = models.DetailAct
Thank you

You can use two Form objects in one <form> tag without problems. Just make sure that you pass prefix="form-1" to one of the forms (or both - as long as the prefixes are different) in your view. See this answer for an example.
Nope, you can't use built-in class based views for this. Or, at least, not on the high-level you'd expect. You can make your own view class or mixin that will work with two forms, but AFAIK Django doesn't provide one.

Related

Inheritance model update to its parent model

I need extend a model from another model.
Case:
core/models.py
class Master(models.Model):
code = models.CharField(max_length=30, unique=True)
name = models.CharField(max_length=100, blank=False, null=False)
class Meta:
abstract = True
class City(Master):
zipcode = models.IntegerField()
custom/models.py
from core.models import City
class City(City)
newfield = models.CharField(max_length=20)
custom is an app.
I have tried with proxy model but it is not what I need, since proxy model adds a new table. https://docs.djangoproject.com/en/2.2/topics/db/models/#proxy-models
I need is that when I migrate add the new field to City.
More info.
In core the table is created and in custom you can add new fields that the client needs. The idea is that core is only maintained as standard.
Proxy models don't add new tables. From the docs link you mentioned:
The MyPerson class operates on the same database table as its parent Person class.
If you want one table called core_city, and another called custom_city, the second one having an extra field, you simply subclass it. Perhaps it would be easier to use an alias:
from core.models import City as CoreCity
class City(CoreCity):
newfield = models.CharField(max_length=20)
custom_city will have all fields from core_city, plus a newfield. The description of how this works (and an example) is covered in the docs section Multi-table inheritance.
If what you want is to have one single database table, then you should use a proxy Model, however they really don't allow you to create new fields. The field should be created in the parent model, or otherwise exist in the database and not be handled by Django migrations at all.
You are looking for Abstract base classes models:
Abstract base classes are useful when you want to put some common information into a number of other models. You write your base class and put abstract=True in the Meta class.
This is the base class:
#core/models.py
class City(Master):
zipcode = models.IntegerField()
class Meta:
abstract = True # <--- here the trick
Here your model:
#custom/models.py
from core.models import City as CoreCity
class City(CoreCity):
newfield = models.CharField(max_length=20)
For many uses, this type of model inheritance will be exactly what you want. It provides a way to factor out common information at the Python level, while still only creating one database table per child model at the database level.
You can update or create your class constants after its defined like this
from core.models import City
City.newfield = models.CharField(max_length=20)
You may need to use swappable models, using them you can define a City class and change it with whichever model you need later,
but that way you can't import and use the base City model directly, you may need to provide a method like get_city_model for that, as your public API.
class City(Master):
zipcode = models.IntegerField()
class Meta:
swappable = 'CORE_CITY_MODEL'
and maybe replace it later with some other model, then just set CORE_CITY_MODEL to that model in the form of 'app_name.model_name'.
The django.contrib.auth is a good example of this, you may consider checking User model and get_user_model method. Although I think you may face problems if you change your city model after you did run migrate, it may not move your data to the new table, but I'm not sure about this.

Is it possible to view m2m relation in the admin view of the model that didn't define it?

I have two models and one of them defines m2m relation.
For example:
class A(models.Model)
name = models.Charfield(max_length=64)
class B(models.Model)
style = models.ManyToManyField(A, blank=True)
When I view instance of B in the admin interface I can see style field with instances of A that I can multi-select.
Is there a way for me to see which instances of B are related to an instance of A when I view it in the admin interface?
Yes, that is possible with InlineModelAdmin.
See an example in the docs: https://docs.djangoproject.com/en/dev/ref/contrib/admin/#working-with-many-to-many-models

Django form exclude options in select field

I have one model that has a ManyToMany Field (let's call it "Options") with another Model
When I create the ModelForm it displays all options.
Is there any way to exclude some option values or to show only some of them?
Here is an example:
models.py
class Options (model.Models):
name = ...
...
class Anything (model.Models):
...
options = ManyToManyField(Options)
values of "Options" in my DB:
["OK",
"OK_2",
"NOT_OK",
"OK_3,
"NOT_OK_2"]
Let's say that I need to show ONLY the "OK" values and hide or not to show the "NOT_OK" values.
Is there any way to do this with ModelForms?
You certainly can filter the queryset for a foreign key field or m2m on the related model by using a Form or more commonly a ModelForm.
The reason doing this at form level is useful is because that filtering could well be based on business logic which is not applicable in all cases and so allows more flexibility than defining it against the model for example.
While you can do this while defining the form fields it is best to do it once the form has been constructed and so it takes place at runtime and not compile time (I have just experienced a few interesting occasions where this has caused me some issues, however that was an earlier version of Django!)
The following ModelForm would do the job:
class AnythingForm(ModelForm):
options = forms.MultipleChoiceField()
def __init__(self, **kwargs):
super(AnythingForm, self).__init__(self, **kwargs)
self.fields['options'].queryset = Option.objects.filter({pass in your filters here...})
class Meta:
model = Anything
You can pass the limit_choices_to parameter to your ManyToMany field:
from django.db.models import Q
class Anything (models.Model):
options = models.ManyToManyField(Options,
limit_choices_to=Q(name__startswith='OK'))
In django 1.7 you can even pass a callable in case if list of choices should be changed dynamically.

How to make superclass querysets return subclass objects? Or downcast the superclass queryset to a subclass list?

I'm working in a django project which I need to list two different models in the same view ordered by date. In order to achieve that I used inheritance to be able to get them all into a generic queryset. My models are:
class Publication(models.model):
title = models.CharField(max_lengh = 200)
pub_date = models.DateTimeField(default = datetime.now)
headline = models.TextField()
class Meta:
abstract = True
#abc.abstractmethod
def say_hello(self):
return
class New(Publication):
author = models.ForeignKey(Author)
source = models.CharField(max_length = 200)
categories = models.ManyToManyField(Category)
url = '/news/'
def say_hello(self):
return "Hello New!!!"
class Opinion(Publication):
writer = models.ForeignKey(Writer)
style = .models.CharField(max_length=3, choices=(('txt', 'Text'), ('glr', 'Galery')))
url = '/opinions/'
def say_hello(self):
return "Hello Opinion!!!"
I'm trying to call the subclass method while iterating through the Publication QuerySet like this:
publications = Publications.objects.all().order_by('-pub_date')
for pub in publications:
pub.say_hello()
url = pub.url
The problem is that my QuerySet is returning Publication objects, so I can't access child attributes and methods, obviously cus I'm dealing with Publication objects. Shouldn't The fact that I've set Publication as an abstract class, avoid the possibility of dealing with Publication objects?. Shouldn't they be prevented from being instantiated? Is there any option for perform perform a QuerySet in Publication class and return a list with child objects?
If no. How would you guys go around this situation? I could really use some tips.
Sounds like it might be appropriate to use multi-table inheritance and django polymorphic:
Multi-table inheritance: https://docs.djangoproject.com/en/dev/topics/db/models/#multi-table-inheritance
Django polymorphic: http://django-polymorphic.readthedocs.org/en/latest/
Multi-table inheritance in django allows you to have a base model/table which has your base fields. Your subclasses then define the extended fields which are put in their own tables. When you fetch records with querysets from any of the subclasses, you'll get information for each record from both the base model/table and the subclass model/table.
In order to fetch records using the base model's queryset, and get an instance of the appropriate subclass for each result, one option is django polymorphic. I've used it before and it works pretty well. It definitely has its limitations but I'd give it a shot.
Each Publication instance should have either a 'new' attribute or a 'opinion' attribute pointing to one of the two subclasses respectively. Be aware that each instance has only one of this attributes so maybe it's better to try...except access to them.
Well, I will put the code for my solution here which I achieved thanks to #David answer.
As suggested for David, I used django-polymorphic, which is great and simple. But the fact that I already had a populated database, made things a bit complicated. Nothing hard to fix.
First thing I did was to migrate the database with south in order to add the new field (polymorphic_ctype) to my parent model (no field is added to the subclasses).
Then, I used the following code in django shell mode on terminal. (python manage.py shell)
from jornal.models import Publication, New, Opinion
from django.contrib.contenttypes.models import ContentType
ctype_opinion = ContentType.objects.get(model = 'opinion', app_label = 'jornal')
ctype_new = ContentType.objects.get(model = 'new', app_label = 'jornal')
opinions = Opinion.objects.non_polymorphic().all()
news = New.objects.non_polymorphic().all()
for new in news:
new.polymorphic_ctype = ctype_new
new.save()
for opinion in opinions:
opinion.polymorphic_ctype = ctype_opinion
opinion.save()

Django Form with a one-to-many relationship

I have a form in Django called PersonForm this forms model has a one-to-many relationship with Car. When displaying the PersonForm just like in the Django Admin I would like to allow my users to select/deselect from a list of Cars etc. Is this possible? I'm looking for information on where to start.
This is what I have so far for the PersonForm:
class PersonForm(forms.ModelForm):
class Meta:
model = Person
fields = ('description',)
The Models:
class Person(models.Model):
description = models.CharField(max_length="150")
class Car(models.Model):
make = models.CharField(max_length="25")
owner = models.ForeignKey('Person', related_name="Car")
So in the person form I need to show a list of cars that person is the owner of an allow selecting/deselecting of them. I'm assuming I can do this in the form i.e. using something like the related name.
Sounds like you want an inline model form. This give you the ability to add/remove Car objects from a Person within the Person form.
That previous link was for inlinemodeladmin. This next link is for an inline form:
https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#modelforms-factory
I didn't have any chance with inline formset, so i would suggest to override your save method of the model, i feel it's more DRY:
class PersonForm(forms.ModelForm):
# add a field to select a car
car = forms.ModelChoiceField(car.objects.all())
class Meta:
model = Person
fields = ('description', 'car')
def save(self, commit=True):
instance = super().save(commit)
# set Car reverse foreign key from the Person model
instance.car_set.add(self.cleaned_data['car']))
return instance
I know this is an old thread, but since I found myself almost exclusively pointed here by google when searching, I thought I would include the following for anyone else looking for an answer.
The answer, I think, is to use
https://docs.djangoproject.com/en/3.1/ref/forms/fields/#modelchoicefield
or
https://docs.djangoproject.com/en/3.1/ref/forms/fields/#modelmultiplechoicefield
There is a good article on how to use the modelmultiplechoicefield at :
https://medium.com/swlh/django-forms-for-many-to-many-fields-d977dec4b024
But it works for one to many fields as well. These allow us to generate a form with multiple choices as checkboxes or similar widgets based upon a related field in a model.

Categories

Resources