I'm new to django and while the admin site is useful I need to be able to do simple functions without it. I would like to automatically manage my objects.
Is it possible to create objects outside of the admin site?
I know one way to do it
Class Foo (models.Model):
name = models.CharField(max_length=100)
def __unicode__(self):
return self.name
def create(cls, name, url):
bar = cls(name=name)
return bar
s1 = Foo.create("THIS IS A NAME")
s1.save()
But I'm having trouble adding new variable to the object
How do I add unique variables to each object
thanks
Sorry I am not sure about your question. If you want to have a unique field for your model you can do
yourUniqueFieldName = models.TextField(max_length=100, unique=True)
And this for a pair of (or more) unique fields you can do
class Meta:
unique_together = ('field1', 'field2',)
Official documents is always your best friend as a start:
https://docs.djangoproject.com/en/dev/ref/models/fields/
Related
I have the following models example:
class TestSet(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return self.name
class Class(models.Model):
name = models.CharField(max_length=50)
test_set_id = models.ForeignKey(TestSet)
def __str__(self):
return self.name
class Test(models.Model):
title = models.CharField(max_length=50)
test_set_id = models.ForeignKey(TestSet)
def __str__(self):
return self.title
class ClassTest(models.Model):
class_id = models.ForeignKey(Class)
test_id = models.ForeignKey(TestSet)
memo = models.CharField(max_length=250)
def __str__(self):
return self.memo
What I want to do is when a new Class or Test is created, it should also create automatically a ClassTest entry if their test_set_id matches with the currenct entries on the database.
Example:
Lets say I already have three Test objects with test_set_id = 1
I create a new Class object with test_set_id = 1
After creating the new Class object, the program should also create 3 new entries in the ClassTest model connecting classes to tests based on the match of the test_set_id field.
It should work the same if a new Test object is added.
So there are two answers that comes in mind:
You can use Django Signals to create a receiver that execute a specific command when a Class object is created. Something around the code below. Consider that the instance is basically the just created class and you can simply operate standard django query with that do get and create additional objects.
#receiver(post_save, sender=Class)
def create_test_sets(sender, instance, created, **kwargs):
if created:
///do things///
On a second beat thought, I would ask what's the overall use-case your are trying to solve. I feel there is some redundancy here but I can't fully figure out where unless you help me gather the bigger picture.
Okay, so I have two Django models:
class Ticket(BaseModel):
name = models.CharField(max_length=200)
description = models.TextField(blank=True, null=True)
def get_absolute_url(self):
return '/core/group/ticket/{0}/'.format(self.id)
class ProjectTicket(Ticket):
project = models.ForeignKey('Project', on_delete=models.DO_NOTHING)
phase = models.ForeignKey('ProjectPhase', blank=True, null=True, on_delete=models.DO_NOTHING)
def get_absolute_url(self):
return '/different/url/structure'
Now, I'm querying all Ticket objects with Ticket.objects.all(). This will return all Ticket objects, including some that are ProjectTicket subclasses.
What I'd like to be able to do is access the subclass get_absolute_url() when the objects in question are actual subclassed ProjecTicket objects.
I know that I can get the parent class from the subclass, but I want to be able to do the reverse.
Has anyone achieved something like this? If so, what approach did you take?
Here's one way that I can think of right now:
I'm sure you know that inheriting django models creates a OneToOne relationship with the parent. So, the Ticket objects which are also instances of ProjectTicket class, will have an attribute called projectticket on them. You can check for this value and return the url accordingly:
class Ticket(...):
...
def get_absolute_url(self):
if hasattr(self, 'projectticket'):
return self.projectticket.get_absolute_url()
else:
return '/core/group/ticket/{0}/'.format(self.id)
I need to implement the following:
The user shall be presented with a form that will have a drop down choice menu consisting of property names. There are two types of properties: general properties, i.e. properties common for all users and custom properties, i.e. properties that each user has defined prior to that. The models would look something like that:
class GeneralPropertyName(models.Model):
name = models.CharField(max_length=20)
class CustomPropertyName(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=20)
The drop down menu should have all general properties and only those custom properties that pertain to the user.
First question: how to define such a model?
I need to: 1. somehow unify both properties, 2. take only those items from CustomPropertyName that pertain to the user
class SpecData(models.Model):
user = models.ForeignKey(User)
selection_title = models.CharField(max_length=20)
property = ForeignKey(GeneralPropertyName) ??UNIFY??? ForeignKey(CustomPropertyName)
Second, is there anything special that needs to be done with ModelForm?
class SpecDataForm(ModelForm):
class Meta:
model = SpecData
And the 3rd question is what needs to be done in the view? I will need to use inline formsets since I will have a few dynamic forms like that.
def index(request):
user = User.objects.get(username=request.user.username)
specdataFormSet = inlineformset_factory(User, SpecData, form=SpecDataForm, extra=30)
...
specdata_formset = specdataFormSet(instance=user, prefix='specdata_set')
...
Thanks.
EDIT: Adjusted juliocesar's suggestion to include formsets. Somehow I am getting the following error message: Cannot resolve keyword 'property' into field. Choices are: id, name, selection_title, user
def index(request):
user = User.objects.get(username=request.user.username)
user_specdata_form = UserSpecDataForm(user=user)
SpecdataFormSet = inlineformset_factory(User, SpecData, form=user_specdata_form, extra=30)
You can use a GenericForeignKey to handle it, but you still need more to solve your further questions about forms and view.
I have made an example of how you solve your problem (logged user can select from General properties and his Custom properties, non-logged user only can select General properties). I used model inheritance for the properties (In your sample code it seems that a CustomPropertyName is a PropertyName with other fields). I think inheritance is an easier and a more basic concept than ContentTypes and it fits to your needs.
NOTE: I remove some code like imports to simplify the code.
1) models.py file:
class PropertyName(models.Model):
name = models.CharField(max_length=20)
def __unicode__(self):
return self.name
class CustomPropertyName(PropertyName): # <-- Inheritance!!
user = models.ForeignKey(User)
def __unicode__(self):
return self.name
class SpecData(models.Model):
user = models.ForeignKey(User)
selection_title = models.CharField(max_length=20)
property = models.ForeignKey(PropertyName)
NOTES: The field SpecData.property points to PropertyName since all properties are saved in the PropertyName's database table.
2) forms.py file:
from django import forms
from django.db.models import Q
from models import SpecData, PropertyName
def UserSpecDataForm(user=None):
UserPropertiesQueryset = PropertyName.objects.filter(Q(custompropertyname__user=None) | Q(custompropertyname__user__id=user.id))
class SpecDataForm(forms.ModelForm):
property = forms.ModelChoiceField(queryset=UserPropertiesQueryset)
class Meta:
model = SpecData
exclude = ('user',)
return SpecDataForm
NOTES: The trick here is to generate the form SpecDataForm dynamically, by filtering properties according the user specified in the parameter.
3) views.py file:
from forms import UserSpecDataForm
def index(request):
if request.POST:
form = UserSpecDataForm(request.user)(request.POST) # instance=user
if form.is_valid():
spec_data = form.save(commit=False)
spec_data.user = request.user
spec_data.save()
else:
form = UserSpecDataForm(request.user)()
return render_to_response('properties.html', {'form': form}, context_instance=RequestContext(request))
NOTES: Nothing special here, just a call to form.UserSpecDataForm(request.user) that returns the form class and then instantiate. Also setted the logged-in user to the object returned on save since It was excluded in the form to not show in front-end.
Following this basic example you can do the same with formsets if you need it.
UPDATE:
Formset can be used by adding following code to the view:
user_specdata_form = UserSpecDataForm(user=request.user)
SpecdataFormSet = inlineformset_factory(User, SpecData, form=user_specdata_form, extra=30)
The complete project sample can be downloaded from http://ge.tt/904Wg7O1/v/0
Hope this helps
1a) have you looked into django's ContentType framework this will allow you to have generic foreign keys and you can put restrictions on what types of models are acceptable to store in.
1b) I think that the validation for accepting what type of foreign key is acceptable shouldn't be in your model but should be part of your form validation before saving.
2) If you do use a model form you're going to have to define your own custom widget for the propery field. This means you're probably going to have to write you're own render function to render the html from the field. You should also define your own validation function on the form to make sure that only the appropriate data is acceptable to save.
3) I don't think you'll have to do anything you aren't already doing in the views
Use GenericForeignKey:
class SpecData(models.Model):
user = models.ForeignKey(User)
selection_title = models.CharField(max_length=20)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
property = GenericForeignKey('content_type', 'object_id')
You can use this to combine the two fields(type & id) into a single choice field.
One way is that you have only one model, make user nullable:
class PropertyName(models.Model):
user = models.ForeignKey(User, null=True, blank=True)
name = models.CharField(max_length=20)
class SpecData(models.Model):
user = models.ForeignKey(User)
selection_title = models.CharField(max_length=20)
property = ForeignKey(PropertyName)
So, if user is not set, it is a general property. If it is set, it is related to this user.
However, please note that if you need unique property names, that NULL != NULL.
Of course, the suggested GenericForeignKey solution is better for some cases.
Also, you can easily make the normal (non-model) form with that you describe and separate form logic from model logic.
lets assume I have following model:
class Note(models.Model):
user = models.ForeignKey(User)
pub_date = models.DateTimeField()
title = models.CharField(max_length=200)
body = models.TextField()
def __unicode__(self):
return self.title
I need a function that will work like this:
print inspectModelClass(Note)
>>> {user:('ForeignKey', {null:False, unique:False, blank:False...}), pub_date:('DateTimeField',{null:False, unique:False,...})...}
I don't know how to list only instances of django.model.field, how to get their names, proper types (BooleanField, CharField, etc.) and their properties like null, unique, max_chars etc.
Can you help me with that?
The reason I need this is that having such a function I would be able to dynamically create Index classes for django-haystack.
You can get Model fields properties easily using the class Metadata.
MyModel._meta.fields
return a list of the fields.
Every field in this list has your well known attributes (name, verbose_name etc.)
How can i update the existing object of intermediate model using generic view?
class Person(models.Model):
name = models.CharField(max_length=128)
def __unicode__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
def __unicode__(self):
return self.name
class Membership(models.Model):
person = models.ForeignKey(Person)
group = models.ForeignKey(Group)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
Currently i'm using generic views concept to update object, but I'm facing problem hoe to update field which exist in intermediate model?
If i generate modelform for Group class, then how can i update the associated field (intermediate model field) using generic view concept?
In above i want to update invite reason field
Thanks in advance
I think there are some missing views in generic or class-based views (which I highly recommend you if your are not already using them), and other people thinks in the same way...
Take a look at django-extra-views project, it implements those missing views.