I have 5 classes, Customer, Supplier, Order, Design and OutSource.
The Order has 3 relationships, one to one with Customer, many to many with Designand one to one with OutSourse. first I just did add its one to one relationship withCustomer(customer=models.ForeignKey(Customer)), now I wanna add the those 2 relationships withDesignandOutsourse`.
design=models.ManyToManyField(Design)
outSource=models.OneToOneField(OutSource)
when I do that and run the "makemigrations" command I get this error--> "NameError:name "Design" is not defined"
without those 2 lines of code I can migrate without any kinda problem...can't figure out where I'm going wrong.
any help will be appreciated.
models.py
class Order(models.Model):
o_type=models.CharField(max_length=15, verbose_name='Order type')
number=models.IntegerField()
date=models.DateField()
status=models.CharField(max_length=25)
delivery_date=models.DateField()
customer=models.ForeignKey(Customer)
design=models.ManyToManyField(Design)
outSource=models.OneToOneField(OutSource)
class Design(models.Model):
dimension=models.IntegerField()
image=models.ImageField(upload_to='images/%Y/%m/%d')
number_of_colors=models.IntegerField()
sides=models.IntegerField(verbose_name='side(s)')
class OutSource(models.Model):
date=models.DateField()
number=models.IntegerField()
description=models.CharField(max_length=100)
code=models.IntegerField()
supplier=models.ForeignKey(Supplier)
You are declaring the class Design after actually defining the ManyToManyField relationship. It cannot find the class with name Design and hence the NameError.
Declare the class Design before class Order and things should work for you.
Related
I have been trying to figure out the best way to automate creating multiple SQL tables based on separate but identical models, all based on the same base class. I'm basically creating pseudo message boards or walls with different Groups, and I wanted each Group to have its own db_table of Posts, each Post containing the user id, timestamp, etc.
My first thought was to have one base class of Posts and just include a field for Group name, but I thought this would be bad practice. My rationale was that one table containing every Post for all Groups would get really big (in theory anyway) and slow down filtering, and also that the extra field for group name would in the long run be a waste of memory when I could have separate tables per group and skip this field.
I've also considered using a ForeignKey with a Many-to-One relationship, but as far as I can tell this has the same drawbacks. Am I wrong to think that? Or are these size concerns not really an issue?
So my next idea was to make Posts an abstract class, and then create subclasses based on each Group. This is ultimately what I did. However, I found myself having to copy and paste the code over and over and change the class name each time. This felt very unPythonic to me. It was something like:
class Posts(models.Model):
timestamp = models.DateTimeField(auto_now_add=True, unique=False)
user_id = ...
#etc.
#
class Meta:
abstract = True
class GroupA(Posts):
class Meta(Posts.Meta):
db_table = 'groupa_board'
class GroupB(Posts):
class Meta(Posts.Meta):
db_table = 'groupb_board'
class GroupC...etc.
What I really was looking for was a factory function to do this for me. I tried this sort of thing:
def makeBoard(group):
class Board(Posts):
class Meta(Posts.Meta):
db_table = group
return board #note I tried with and without this line
And then I ran a simple for loop using a list of groups.
for group in groups:
makeBoard(group)
I found myself hitting a RuntimeError: conflicting models in application, and I probably deserved it. So then I figured what I need is something like:
def makeBoard(group):
class group(Posts): #***group here being a variable, not the class name
class Meta(Posts.Meta):
db_table = '%s' % group #maybe issues here too, but the table
return group #name is not that important if the class
#name works
But I couldn't figure out how to make this work! Is there a way to pass a variable from a list to a class name?
Anyway if you're still with me I appreciate it. I've been on stackoverflow all day and while I've found guides for creating abstract base classes and subclasses to solve similar issues, I didn't see a way to create a function to do this for me. I ultimately punted here and just make a subclass for each group by hand. If there is a way to automate this process, I'd love to hear it.
Also, if I'm being stupid for not just going with one db table containing every post, I'd like to know that too, and why! Or if there's a better way to implement this kind of system altogether. I apologize if this has been answered before, I really couldn't find it.
Thank you!
Using a single table would not be bad practice. The extra memory is minimal, on modern systems that shouldn't be a problem. You shouldn't worry about performance either, premature optimization (not including the actual system design) is considered bad practice, but if you run into performance problems you can always specify an index on the group column:
group = models.CharField(max_length=100, db_index=True)
That's not to say that it is the best option, or that your method isn't good. Also, it is entirely possible to dynamically create models, using the type() built-in function. The only difference with dynamically creating models and creating other classes is that you must specifically pass the __module__ attribute. You can create subclasses for Posts in the following way:
def fabric(names, baseclass=Posts):
for name in names:
class Meta:
db_table = '%s_table' % name.lower()
attrs = {'__module__': baseclass.__module__, 'Meta': Meta}
# specify any other class attributes here. E.g. you can specify extra fields:
attrs.update({'my_field': models.CharField(max_length=100)})
newclass = type(str(name), (baseclass,), attrs)
globals()[name] = newclass
fabric(['GroupA', 'GroupB', 'GroupC', etc...])
Put that code in your models.py after your Posts class, and all classes will be created for you. They can be used in any way normal classes can be used: Django doesn't even know you dynamically created this class. Though your Meta class doesn't inherit from Posts.Meta, your meta settings should still be preserved.
Tested with Django 1.4.
Try smth like this
import app.models as group_models
from django.db.models.base import ModelBase
def fabric(group):
for item in dir(group_models):
c = getattr(group_models, item)
if type(c) is ModelBase:
if c._meta.db_table == '%s_table' % group:
return c
return None
This is code in models.py
class Package(models.Model):
name=models.CharField(max_length=300)
version=models.CharField(max_length=300,blank=True)
home_page=models.URLField(blank=True)
summary=models.TextField()
description=models.TextField(blank=True)
keywords=models.TextField(blank=True)
categories=models.ManyToManyField(Category,related_name='packages')
class Category(models.Model):
topic=models.ForeignKey(Package, related_name="categories")
When i try to syncdb it says "NameError Category is not defined" i tried placing class category first and package next this time it says "NameError name Package is not defined".
Please help me out of this problem.
EDIT:
Thanks for the help guys, from a very little knowledge of what i know in databases the tutorial here seems wrong http://toys.jacobian.org/presentations/2007/pycon/tutorials/beginning/
He has defined the field categories in Packages to be many-to-many and the field in Category topic to be a foreign key to Package ,but a foreign key is a many-to-one relationship, therefore the implementation is flawed.
I think django is trying to tell it in its way as "Accessor for field 'topic' clashes with m2m field 'Package.categories'." Reverse query name for field 'topic' clashes with m2m field ' "
Is that correct?
"If you need to create a relationship on a model that has not yet been defined, you can use the name of the model, rather than the model object itself..."
class Package(models.Model):
...
categories=models.ManyToManyField('Category', related_name='packages')
Add quotes while you define category ManyToManyField.
Change to:
categories=models.ManyToManyField('Category',related_name='packages')
Reason: Category is not defined while you add that field, so need to add quotes around it so that django will resolve it later.
I have a legacy database with non-django naming conventions. If I have the following (cut down) models:
class Registration(models.Model):
projectId=models.IntegerField(primary_key=True)
class Application(models.Model):
applicationId=models.IntegerField(primary_key=True)
registration=models.ForeignKey(Registration,db_column='projectId')
The ForeignKey instance causes a property to be created on Application called registration_id, but this is neither the correct name for the field (I have a hack to fix this), nor is it able to be used in a QuerySet.
Is there some way of using the id field provided by the ForeignKey on the Application model, rather than having to reference it via Registration?
Ie. I write lots of code like:
Application.objects.get(projectId=1234)
And don't want to have to write it out as:
Application.objects.get(registration__projectId=1234)
or even
Application.objects.get(registration__pk=1234)
I'm slightly surprised that:
Application.objects.get(registration_id=1234)
doesn't work...
Also note, I tried defining the id column as a field as well as the foreignkey which worked for queryset, but inserts complain of trying to insert into the same column twice:
class Application(models.Model):
...
projectId=models.IntegerField()
...
Have you tried this?
Application.objects.get(registration=1234)
I think just doing Application.objects.registration.get(projectId=1234) should do what you want.
I'm working on my first real Django project after years of PHP programming, and I am running into a problem with my models. First, I noticed that I was copying and pasting code between the models, and being a diligent OO programmer I decided to make a parent class that the other models could inherit from:
class Common(model.Model):
name = models.CharField(max_length=255)
date_created = models.DateTimeField(auto_now_add=True)
date_modified = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.name
class Meta:
abstract=True
So far so good. Now all my other models extend "Common" and have names and dates like I want. However, I have a class for "Categories" were the name has to be unique. I assume there should be a relatively simple way for me to access the name attribute from Common and make it unique. However, the different methods I have tried to use have all failed. For example:
class Category(Common):
def __init__(self, *args, **kwargs):
self.name.unique=True
Causes the Django admin page to spit up the error "Caught an exception while rendering: 'Category' object has no attribute 'name'
Can someone point me in the right direction?
No, Django doesn't allow that.
See the docs: http://docs.djangoproject.com/en/1.1/topics/db/models/#field-name-hiding-is-not-permitted
Also answered in other questions like: In Django - Model Inheritance - Does it allow you to override a parent model's attribute?
You have a small mistake in your Common class
class Common(model.Model):
self.name = models.CharField(max_length=255)
should be
class Common(model.Model):
name = models.CharField(max_length=255)
Note that UNIQUE constraint in fact has nothing to do with Django, so you're free to add it in your database table. You can also use post-syncdb hook for that purpose.
Try using Meta.unique_together to force it into its own unique index. Failing that, it's probably easiest to create two separate abstract classes, one with the field unique and one not.
I have 2 models with a 1-1 relation (essentially a resource pool). For the example code, I will simply use nuts and bolts. There will be many more nuts (available resources) than bolts (which will each require 1 nut). However, if a nut can only be assigned to one bolt.
The constraint is easy enough to set up with the unique=True named param to the ForeignKey method.
The problem arises from the ModelForm. When rendered, the form will contain every nut in the dropdown. I would like to restrict it to only show nuts that haven't already been claimed by a bolt.
I am aware of the fields attribute of the ModelForm class, but am unable to come up with a query set filter that adequately addresses the issue. Here is example code of my problem:
from django.db import models
from django.forms import ModelForm
# Create your models here.
class Nut(models.Model):
size = models.CharField()
class Bolt(models.Model):
size = models.CharField()
nut = models.ForeignKey( Nut, unique=True )
class BoltForm(ModelForm):
def __init__(self, *args, **kwargs):
super(BoltForm, self).__init__(*args, **kwargs)
self.fields['nut'].queryset = # All unassigned nuts
Try this:
self.fields['nut'].queryset = Nut.objects.exclude(
pk__in=Bolt.objects.values('nut').query)
Update:
Of three expressions generating the same sql query:
pk__in=Bolt.objects.values('nut')
pk__in=Bolt.objects.values_list('nut')
pk__in=Bolt.objects.values('nut').query
I'd choose the last one as most straight-forward (although in other two cases the list and dict aren't created in fact: django 'understands' the intention without explicit mentioning of .query)
Also, consider Daniel Roseman's answer. It is another approach to do the same thing.
Nut.objects.filter(bolt=None)