How do I hard-code a type into my models in Django - database

Here's the logic for the models:
Category. There are several categories; each category can contain several products.
Product. There are several products; each product can only have one category.
Is it possible to specify what kind of category each product is within the model file itself? For example: can I set the model so that a shirt can only be clothing and nothing else?
Here's what I have so far (it doesn't validate):
class Category(models.Model):
CATEGORY_CHOICES = (
('CLOTHING', 'Clothing'),
('FURNITURE', 'Furniture'),
)
category = models.CharField(choices=CATEGORY_CHOICES)
class Shirt(Product):
category = models.ForeignKey(Category, default=CATEGORY_CHOICES.CLOTHING)
class Table(Product):
category = models.ForeignKey(Category, default=CATEGORY_CHOICES.FURNITURE)
I'm new at this. Thanks for the help!

You can validate your model on save with any arbitrary rules. So, write a validation rule that checks that all shirts are saved in the category clothing.
For user input, create a form that only provides choices corresponding to the product.
Good luck!

I suggest that you invest some time into adopting recently added model validation, while it's not automatic as forms validation (you'll have to call clean* methods yourself, probably inside save), you gonna get DRY validation that could be used on Model and Form level.

You can use callables to give instance as a default value
Something like this (untested code):
class Shirt(Product):
def getClothingInstance():
return Category.objects.get(category=Category.CATEGORY_CHOISES['CLOTHING'])
category = models.ForeignKey(Category, default=getClothingInstance)

Related

Search/Filter Dropdown in Django Admin Panel for standard CharField

I am using Django to build data models including a model Company. Some of the fields belonging to this model are limited to set choices using the choices='' argument. Some of these fields have a large number of choices, for example a country CharField which lists all countries. Finding the right value among the long list can be tedious so I want to be able to search across the given choice values. This is easy to do for ForeignKey/ManytoMany fields using autocomplete_fields = [] as seen in the attached screenshot (from a different model) but can't seem to find a method for implementing this with a normal CharField with lots of choices. This seems like something that should be built into the Django for the admin panel but I can't find anything within the docs. Please how can I implement a search/filter dropdown for any given (non FK/m2m) fields? Thanks in advance. If there's anymore information I can provide let me know and I will.
country = models.CharField(max_length=128, choices=COUNTRY_CHOICES, null=True)
Model code added. This COUNTRY_CHOICES array is what I would like to be able to select from in a searchable dropdown list.

Django, relate User with another table

So I got the tables you can see in the image below:
.
What I would like to do is to create a relationship so that each user (of django auth_user) will be enrolled(or able to enrol) to exactly one "course" so that he will be able to see next events for his modules.
Do I have to create another table and place 2 foreign keys or this is a way to do it in 'php' and it's more simple with Django? I was suggested to create 'student' model inheriting from 'User' with extended behavior and one to many relationship on auth. I tried to do that but unfortunately had not results since I'm really new to Django & Python.
If every auth_user (or auth.User) will be or have the opportunity to be enrolled on a course I would create a 'user profile' model that has a 1-to-1 relationship with the django User model. You can store additional User data in this model, including what course they are enrolled on. See https://docs.djangoproject.com/en/dev/topics/auth/customizing/#extending-the-existing-user-model for more details but here is an example:
class UserProfile(models.Model):
user = models.OneToOneField('auth.User')
course = models.ForeignKey('courseapp.Course', null=True)
You would probably need to create a signal that gets fired each time an auth.User object is saved, such that if it is the first time that User object has been saved, it automatically creates the UserProfile:
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from yourusersapp.models import UserProfile
def create_user_profile(sender, instance, created, **kwargs):
# Automatically creates a UserProfile on User creation.
if created:
UserProfile.objects.create(user=instance)
post_save.connect(create_user_profile, sender=User)
When you query a User object, you can then reference the User object's profile like:
user_object.userprofile
You could then create a Course object and link the user_object indirectly via its UserProfile to that Course:
course = Course.objects.create(name='course_name', next_field='whatever')
user_profile = user_object.userprofile
userprofile.course = course
userprofile.save()
Now you have a user object with a UserProfile that is linked to only 1 course. Many users can be on the same course, but a user can only be on 1 course. You can also reference all users on a particular course like:
course = Course.objects.get(name='course_name')
course_users = course.userprofile_set.all()
HTH
I think that you can go about this one of two ways.
Extend the User model. 'Student' would probably be a good name for your new model. It would have a OneToOne relationship with 'User', and a ForeignKey relationship with 'Course'. It can store any other information that is applicable to students only. Documentation for how to do that can be found here https://docs.djangoproject.com/en/1.6/topics/auth/customizing/#extending-the-existing-user-model
Create a custom User model that has a ForeignKey relationship with Course. This approach is a bit more complicated, but yields a slightly cleaner end result. Documentation for that is here. https://docs.djangoproject.com/en/1.6/topics/auth/customizing/#substituting-a-custom-user-model
Sorry if it seems like I'm just sending you to the Django docs, but both of those sections are well written and should explain things pretty clearly. If you'd like to post another question with example code we can try and see why your original attempt at extending the User model didn't work. By the way, your "Student" model shouldn't have to inherit from the User model in order to extend it.

How does cakePHP naming convention work?

I'm relatively new to PHP. Started learning PHP, but then come across cakePHP, which is suppose to speed up development time.
After reading the documentation and blog tutorial I still don't understand the naming convention. I guess I won't know until I start to do some examples, but to get me started can someone please explain to me how cakePHP associate database tables to the controller/model layer?
The below code is an abstract from the tutorial. It is a controller method that passes the post id to the view layer. The database table is called "posts". $this->Post refers to the model class of Post, which correlates to the plural form of posts in the database.
public function view($id = null) {
$this->Post->id = $id;
$this->set('post', $this->Post->read());
}
OK I get that. Then, in the documentation it refers to the following correlation:
ReallyBigPerson and really_big_people
So it seems like the correlation actually follows the rule in English semantics. Does this mean that cakePHP has a list of singular and plural words hidden somewhere that it works from? For example can I use the below correlation without breaking the code?
This and these or Man and men or Foot and feet or Moose and moose or Goose and geese
Furthermore, if I have both singular and plural form of tables in my database, will it break the code, or will it just associate to the plural-formed table?
Just find it baffling... Why couldn't they just match the naming convention like for like with prefixes?
Inflector
CakePHP uses its Inflector class to determine the plurals of things.
Since the naming conventions dictate that model names are singular and tables names are pluralised, it uses the inflector to apply English semantics / rules to determine the plural.
If you need some help understanding the output of the Inflector, you can use the CakePHP inflector website.
Pluralisation Examples
Model name: Post
Table name: posts
Model name: User
Table name: users
Model name: Sheep
Table name: sheep
Model name: News
Table name: news
Model name: Radius
Table name: radii
Check the Inflector site to be sure.
Non-standard Table names
While CakePHP offers a standard rule set for naming and conventions, none of it is set in stone. If you want to change the name of the table used for a particular model, simply specify the table name in the model:
class Thing extends AppModel {
public $useTable = 'somethings';
}
Or, if you want a model that does not use a table:
class Post extends AppModel {
public $useTable = null;
}

cakephp how to have a controller class that other controllers extend

I want a ThingsController that extends AppController. My individual controllers will extend ThingsController. The functions are repetitive for each model, and each model has its own mainly redundant controller.
A) Is this a good idea?
B) How do I do it? I tried adding it to the controllers directory, but cake did not find it.
c) How should I code in beforeFilter and beforeRender? That includes Auth.
It will work fine. Controllers are nothing more than php classes, you can have them inherit any way you like, so long as Cake can find them.
Create your ThingsController and place it in app/controllers/things_controller.php
In your derived controller, add App::import('Controller', 'Things'); above the class definition.
Define the class properly: class TestController extends ThingsController {}
Filters will inherit like normal.
nowadays you can use App::uses('ClassName', 'Folder/Subfolder')
extending a class does nothing for you in terms of tables in the database... as soon as you extend a model, your extended model name is the table name that cake will look for in the database. you don't get to store the common fields in a common table, and the extended fields in the extended class' table. for that you need model associations anyway, so there's not much point extending models and controllers in cakePHP. to have multiple models deal with the same table, you'd override the table the model uses in the Model definition with $useTable, but I can't imagine much point in that other than your project needs to talk to tables that you can't rename.
so in your case I would say Automobile extends AppModel, Car extends AppModel, Truck extends AppModel, (normal cake models) Truck $belongsTo Automobile, Car $belongsTo Automobile. put your common properties and methods in Automobile just like as if you were going to extend from Automobile, and instead of inheriting the methods, you access them by model association as in $this->Truck->Automobile->vin with object notation rather than with $this->Truck->vin which is what you want to do with inheritance.
in other words you won't get any closer to database normalization by extending Models in cakePHP -- that is done through model associations. you inherit from AppModel and AppController in order to get the basic methods like find(), save() etc and callbacks like beforeFilter() and afterRender(), etc. WRT your question, when you override the callbacks like beforeFilter() in an extending class, you have to call parent::beforeFilter() inside the method or things will break.
i suppose you could have a table with all the fields for the extended properties in it (table automobile with fields year, vin and also box_length, trunk_litres), then extend Models from the base class and override the table which the extended models use to use the base class table name (class Car extends Auto {$useTable = auto}), but this leaves lots of empty fields in the table and is not a proper normalized table structure. it would be a way to have say, VIN be a unique field among all the extended classes without much effort though. not sure how the auto_increment for the ID works in that case though. but then it takes extra work to extract from that common table records of a given type that match the extended class' type (table auto has field auto_type, class Truck extends Auto {$autoType = 'truck'}), so no gain.
similarly there is no gain with views. if you have class AutoController extends AppController { function displayListing()} and then class TruckController extends AutoController you can call TruckController->display_listing() but unless you tell the action to $this->render('Auto/display_listing') you will need to create a duplicate of the view in /View/Truck/display_listing.ctp, and if you do the override, then the view in View/Auto/display_listing.ctp will have to have many if statements to render the portions of the view specific to Truck or Car, so again, no gain.

DRY unique objects in Django

I want to ensure an object is unique, and to throw an error when a user tries to save it (e.g. via the admin) if not? By unique, I mean that some of the object's attributes might hold the same values as those of other objects, but they can't ALL be identical to another object's values.
If I'm not mistaken, I can do this like so:
class Animal(models.Model):
common_name = models.CharField(max_length=150)
latin_name = models.CharField(max_length=150)
class Meta:
unique_together = ("common_name", "latin_name")
But then each time I refactor the model (e.g. to add a new field, or to change the name of an existing field), I also have to edit the list of fields in the parenthesis assigned to unique_together. With a simple model, that's OK, but with a substantial one, it becomes a real hassle during refactoring.
How can I avoid having to repeat typing out the list of field names in the unique_together parenthesis? Is there some way to pass the list of the model's fields to a variable and to assign that variable to unique_together instead?
Refactoring models is a rather expensive thing to do:
You will need to change all code using your models since field names correspond to object properties
You will have to change your database manually since Django cannot do this for you (at least the version I used the last time when I worked with Django couldn't)
Therefore I think updating the list of unique field names in the model meta class is the least issue you should worry about.
EDIT: If you really want to do this and all of your fields must be "unique together", then the guy at freenode is right and you'll have to write a custom metaclass. This is quite complicated and errorprone, plus it might render your code incompatible to future releases of Django.
Django's ORM "magic" is controlled by the metaclass ModelBase (django.db.models.base.ModelBase) of the generic base class Model. This class is responsible to take your class definition with all fields and Meta information and construct the class you will be using in your code later.
Here is a recipe on how you could achieve your goal:
Subclass ModelBase to use your own metaclass.
Override the method __new__(cls, name, bases, dict)
Inspect dict to gather the Meta member (dict["Meta"]) as well as all field members
Set meta.unique_together based on the names of the fields you gathered.
Call the super implementation (ModelBase.__new__)
Use the custom metaclass for all your unique models using the magic member __metaclass__ = MyMetaclass (or derive an abstract base class extending Model and overriding the metaclass)

Resources